2010-05-05 4 views
5

He visto una publicación muy interesante en el blog Fabio Maulo's. Aquí está el código y el error si no quieres saltar a la url. He definido una nueva clase genérica de este modo:
¿Es esto un agujero en la unión dinámica en C# 4?

public class TableStorageInitializer<TTableEntity> where TTableEntity : class, new() 
    { 
     public void Initialize() 
     { 
      InitializeInstance(new TTableEntity()); 
     } 

     public void InitializeInstance(dynamic entity) 
     { 
      entity.PartitionKey = Guid.NewGuid().ToString(); 
      entity.RowKey = Guid.NewGuid().ToString(); 
     } 

    } 

Tenga en cuenta que InitializeInstance acepta un parámetro, que es de tipo dinámico. Ahora, para probar esta clase, definí otra clase que está anidado dentro de mi clase principal del programa, así:

class Program 
     { 
      static void Main(string[] args) 
      { 
       TableStorageInitializer<MyClass> x = new TableStorageInitializer<MyClass>(); 
       x.Initialize(); 
      } 
      private class MyClass 
      { 
       public string PartitionKey { get; set; } 
       public string RowKey { get; set; } 
       public DateTime Timestamp { get; set; } 
      } 
     } 

Nota: la clase interna "MyClass" se declara privada.
Ahora si ejecuto este código obtengo un Microsoft.CSharp.RuntimeBinder.RuntimeBinderException en la línea "entity.PartitionKey = Guide.NewGuid(). ToString()".
La parte interesante, sin embargo, es que el mensaje de la excepción dice "El objeto no contiene una definición para PartitionKey".
alt text http://img697.imageshack.us/img697/4188/testdl.png

También tenga en cuenta que si cambió el modificador de la clase anidada a pública, el código se ejecutará sin problemas. Entonces, ¿qué piensan ustedes que realmente está sucediendo bajo el capó? Por favor, consulte la documentación que pueda encontrar, por supuesto, si está documentada en algún lugar.

Respuesta

5

El aglutinante intenta llegar a un accesible clase para tratar el objeto como - en este caso, el código de hacer esa llamada no "sabe" acerca de la clase MyClass, por lo que no "sabe" acerca PartitionKey tampoco.

No sé hasta qué punto esto está documentado en la especificación C# 4 - Sé que he tenido una conversación por correo electrónico con Chris Burrows, así que los detalles pueden estar en algún lugar en his blog :) Tenga en cuenta que la vinculación dinámica ha cambiado con el tiempo, por lo que es probable que las publicaciones más recientes sean más precisas con respecto al código RTM.

Yo creo que si se pone PartitionKey en una interfaz pública que implementa la clase privados, que pueden trabajo - pero habría que probarlo.

Hay varios "errores" en torno a la escritura dinámica. implementación de interfaz explícita tiene un problema similar:

public int Count(IList list) 
{ 
    int count1 = list.Count; // Fine 
    dynamic d = list; 
    int count2 = d.Count; // Should work, right? 
} 

Esto producirá un error si se pasa en una matriz - porque aunque IList.Count existe, se implementa de manera explícita en las matrices - así que es un poco como esto:

string[] array = new string[10]; 
Console.WriteLine(array.Count); // Won't compile 

La carpeta trata de tratar el objeto como su tipo concreto, no como IList, de ahí la falla ...

+0

Yo solía pensar que usar dinámico es una forma abreviada de usar simple reflejo antiguo, aparentemente estoy equivocado porque esto funcionaría bien si reemplazaste el implementación de InitializeInstance para usar la reflexión. ¿Podrías dar más detalles sobre eso, por favor? – Galilyou

+0

@Jon: me temo que todavía no entiendo cómo las matrices se salieron con la no implementación de todas las propiedades de la interfaz (aunque fundirla en un 'IList ' te permite llamar a 'Count' !?) - ¿podrías elaborar? ? * (también, ¿quiso decir 'd.Count' más arriba?) * –

+0

No importa, [contesté mi propia pregunta] (http://msdn.microsoft.com/en-us/library/aa288461%28VS.71%29. aspx). –

Cuestiones relacionadas