2009-04-30 14 views
6

No me refiero a fundición dinámica en el sentido de convertir una interfaz inferior o clase base en una clase más derivada, me refiero a tomar una definición de interfaz que he creado y luego convertir dinámicamente a esa interfaz un objeto diferente NO derivado desde esa interfaz, pero compatible con todas las llamadas.¿El C# 4 permitirá "fundición dinámica"? Si no, ¿debería C# apoyarlo?

Por ejemplo,

interface IMyInterface 
{ 
    bool Visible 
    { 
     get; 
    } 
} 

TextBox myTextBox = new TextBox(); 
IMyInterface i = (dynamic<IMyInterface>)myTextBox; 

Esto podría lograrse en tiempo de compilación para los tipos conocidos, y de tiempo de ejecución para las instancias declaradas con dinámica. La definición de interfaz es conocida, como es el tipo (en este ejemplo), por lo que el compilador puede determinar si el objeto admite las llamadas definidas por la interfaz y realizar alguna magia para que tengamos el molde.

Supongo que esto no es compatible con C# 4 (no pude encontrar una referencia), pero me gustaría saberlo con certeza. Y si no es así, me gustaría discutir si debe incluirse en una futura variante del lenguaje o no, y las razones a favor y en contra. Para mí, parece una buena adición para permitir un mayor polimorfismo en el código sin tener que crear tipos completamente nuevos para ajustar los tipos de marcos existentes.

actualización
Para que nadie me acuse de plagio, yo no era consciente de Jon Skeet having already proposed this. Sin embargo, es bueno saber que pensamos en una sintaxis muy similar, lo que sugiere que al menos podría ser intuitiva. Mientras tanto, "tener una idea original" permanece en mi lista de deseos para otro día.

+1

¿No es esto esencialmente tipado estructural (http://en.wikipedia.org/wiki/Structural_typing)? – Noldorin

+0

@Noldorin: Gracias, no sabía que tenía un nombre. Al examinar eso, diría que sí, así es. –

+1

@Jeff: Sí, ahora estoy bastante seguro de que * son * las mismas cosas, a pesar de que algunos de los comentarios en la publicación del blog de Jon Skeet lo describen como tipado de pato (que es sutilmente diferente del tipado estructural). Sea lo que sea, es una muy buena idea ... algo que desear en C# 5 tal vez. :) – Noldorin

Respuesta

3

Creo que eso es problemático. Está introduciendo el acoplamiento entre dos clases que no están acopladas.

Tenga en cuenta el siguiente código.

public interface IFoo 
{ 
    int MethodA(); 
    int MethodB(); 
} 

public class Bar 
{ 
    int MethodA(); 
    int MethodB(); 
} 

public class SomeClass 
{ 
    int MethodFoo(IFoo someFoo); 
} 

¿Esto debería ser legal entonces?

int blah = someClass.MethodFoo((dynamic<IFoo>)bar); 

Se parece que debería ser legal, ya que el compilador debe ser capaz de escribir de forma dinámica barras como algo que implementa IFoo.

Sin embargo, en este punto está conectando IFoo y Bar a través de una llamada en una parte completamente separada de su código.

Si edita Bar porque ya no necesita MethodB, de repente someClass.MethodFood ya no funciona, aunque Bar e IFoo no están relacionados.

De la misma manera, si agrega MethodC() a IFoo, su código se romperá de nuevo, aunque IFoo y Bar aparentemente no están relacionados.

El hecho es que, aunque esto sería útil en casos selectos donde hay similitudes entre objetos que no controla, hay una razón por la que las interfaces deben estar explícitamente unidas a objetos, y la razón es para que el compilador puede garantizar que el objeto lo implemente.

+1

Pero el OP dice explícitamente marcarlo como * dynamic *. Si esto rompe la consistencia. Dynamic o = new object(); o.InvalidMethod(); también debería hacerlo. –

+0

Al usar la etiqueta dinámica, simplemente está resaltando el hecho de que debe acoplar los objetos. ¿Por qué crear una etiqueta dinámica especial, cuando se utiliza la ya existente 'metodología de interfaz' funciona? Quizás podría aclarar su comentario, no estoy seguro de que lo entiendo. – DevinB

+0

El ejemplo que dio no es correcto ya que no está solicitando explícitamente el tipado dinámico. Solicito explícitamente el tipado dinámico, que, si se conocen ambos tipos en tiempo de compilación, el compilador puede utilizar para generar un error de desajuste de tipo, o si en tiempo de ejecución, el DLR puede determinar si existen las llamadas, al igual que debe hacer para las llamadas individuales, ya forma parte del mecanismo de tipo dinámico existente de C# 4. –

1

No es necesario que C# lo admita, ya que se puede implementar muy limpiamente como biblioteca.

He visto tres o cuatro implementaciones por separado (comencé a escribir una antes de encontrarlas). Aquí es el tratamiento más completo que he visto:

http://bartdesmet.net/blogs/bart/archive/2008/11/10/introducing-the-c-ducktaper-bridging-the-dynamic-world-with-the-static-world.aspx

Probablemente será aún más fácil de poner en práctica una vez que el DLR está integrada en el tiempo de ejecución.

Dado que la clase contenedora/reenviadora de una interfaz determinada se puede generar una vez y almacenar en caché, y luego un objeto determinado de tipo desconocido se puede envolver una vez, hay muchas posibilidades de almacenar en caché los sitios de llamadas, etc. el rendimiento debe ser excelente. Por el contrario, creo que la palabra clave dynamic, que es una característica de lenguaje, y una muy compleja, es una digresión innecesaria y potencialmente desastrosa, con un lenguaje de cuerdas que anteriormente tenía una filosofía de tipado estático muy clara, que le dio una dirección obvia para la mejora futura. Deberían haber mantenido eso e hicieron que la inferencia tipo funcione mejor y mejor hasta que la escritura se volvió más invisible. Hay tantas áreas donde podrían evolucionar el lenguaje, sin romper los programas existentes, y sin embargo, no lo hacen, simplemente debido a limitaciones de recursos (por ejemplo, el motivo por el que var no se puede usar en más lugares es porque tendrían que reescribir el compilador y no tienen tiempo).

Todavía están haciendo cosas buenas en C# 4.0 (las características de varianza) pero hay mucho más que se puede hacer para que el sistema de tipo sea más inteligente, más automático y más potente para detectar problemas en tiempo de compilación. En cambio, básicamente estamos obteniendo un truco.

+0

Creo que las motivaciones para incluir la palabra clave dinámica son más que aceptables teniendo en cuenta el infierno que es la interoperabilidad en este momento. Al usar la palabra clave dinámica, mantiene la naturaleza estáticamente tipada del lenguaje y obliga a los desarrolladores a pensar en lo que escriben y a estar implícitos en el uso de tipos dinámicos, en lugar de decirlo, usar la palabra clave de objeto para objetos escritos dinámicamente. Creo que hacer que teclear sea invisible es exactamente lo que no quieres en un lenguaje estáticamente tipado. (Var en varios lugares es más que una reescritura del compilador, es posible una semántica del lenguaje ... –

+0

... cambie como debe incluir reglas sobre quién asigna primero una variable (para que el tipo pueda ser correctamente inferido). Ciertamente no veo la dinámica como un truco, es un gran paso adelante para cosas como la interoperabilidad COM y una buena manera de proporcionar soporte de lenguaje dinámico en un lenguaje estáticamente tipado. El compilador hace enormes cantidades de trabajo con respecto al uso del tipo , pero no estoy seguro de hacer más es una buena idea, ya que puede conducir al desarrollo lento de código incorrecto. El compilador debe hacer cumplir las reglas, sin darnos ninguna manera de ignorarlas. –

+0

Es una manera de proporcionar compatibilidad dinámica con el lenguaje en una lenguaje estático, en mi opinión (ya explicado) es el equivocado. Re: aplicación de reglas, solo estoy hablando del tipo de inferencia que hacen los lenguajes como Haskell. Las reglas se aplican y, por lo tanto, no se pueden ignorar. la nee d decir lo mismo * dos veces * se reduce. Eso tiene que ser algo bueno. –

1

El marco de código abierto Impromptu-Interface hace esto usando el C# 4 y el dlr.

using ImpromptuInterface; 

interface IMyInterface 
{ 
    bool Visible 
    { 
     get; 
    } 
} 

TextBox myTextBox = new TextBox(); 
IMyInterface i = myTextBox.ActLike<IMyInterface>(); 

Puesto que utiliza el DLR También se trabajará con ExpandoObject y DynamicObject.

+0

¿Cómo es eso diferente de solo realizar un elenco? Mi sugerencia original fue una conveniencia del lado del desarrollo que no tiene ningún impacto en el tiempo de ejecución. –

+0

Ese es mi punto, no es diferente, solo que ahora funciona con el tiempo de ejecución como lo está hoy con una sintaxis ligeramente diferente.El costo del tiempo de ejecución es mínimo, genera un proxy muy liviano que se almacena en caché si solo se mira el costo de invocación explícito, es 1 invocación estática + 1 invocación DLR. – jbtule

Cuestiones relacionadas