¿Cómo reflexiono sobre los miembros del objeto dynamic?

Necesito obtener un diccionario de propiedades y sus valores de un objeto declarado con la palabra clave dinámica en .NET 4? Parece que usar reflexión para esto no funcionará.

Ejemplo:

dynamic s = new ExpandoObject(); s.Path = "/Home"; s.Name = "Home"; // How do I enumerate the Path and Name properties and get their values? IDictionary propertyValues = ??? 

Si IDynamicMetaObjectProvider puede proporcionar los nombres de miembros dynamics, puede obtenerlos. Consulte la implementación de GetMemberNames en la biblioteca PCL con licencia de apache Dynamitey (que se puede encontrar en nuget), funciona para ExpandoObject y DynamicObject s que implementa GetDynamicMemberNames y cualquier otro IDynamicMetaObjectProvider que proporciona un metaobjeto con una implementación de GetDynamicMemberNames sin pruebas personalizadas más allá de is IDynamicMetaObjectProvider .

Después de obtener los nombres de los miembros, es un poco más de trabajo obtener el valor de la manera correcta, pero Impromptu lo hace, pero es más difícil señalar solo los bits interesantes y que tengan sentido. Aquí está la documentación y es igual o más rápido que la reflexión, sin embargo, es poco probable que sea más rápido que una búsqueda de diccionario para expando, pero funciona para cualquier objeto, expando, dynamic u original, lo que sea.

En el caso de ExpandoObject, la clase ExpandoObject realmente implementa IDictionary para sus propiedades, por lo que la solución es tan trivial como el casting:

 IDictionary propertyValues = (IDictionary)s; 

Tenga en cuenta que esto no funcionará para objetos dynamics generales. En estos casos, deberá acceder al DLR a través de IDynamicMetaObjectProvider.

Hay varios escenarios para considerar. En primer lugar, debe verificar el tipo de su objeto. Simplemente puede llamar a GetType () para esto. Si el tipo no implementa IDynamicMetaObjectProvider, puede usar reflection igual que para cualquier otro objeto. Algo como:

 var propertyInfo = test.GetType().GetProperties(); 

Sin embargo, para las implementaciones IDynamicMetaObjectProvider, la reflexión simple no funciona. Básicamente, necesitas saber más sobre este objeto. Si es ExpandoObject (que es una de las implementaciones IDynamicMetaObjectProvider), puede usar la respuesta proporcionada por itowlson. ExpandoObject almacena sus propiedades en un diccionario y simplemente puede convertir su objeto dynamic en un diccionario.

Si se trata de DynamicObject (otra implementación de IDynamicMetaObjectProvider), debe usar los métodos expuestos por DynamicObject. DynamicObject no es necesario para “almacenar” su lista de propiedades en ningún lugar. Por ejemplo, podría hacer algo como esto (estoy reutilizando un ejemplo de la publicación de mi blog ):

 public class SampleObject : DynamicObject { public override bool TryGetMember(GetMemberBinder binder, out object result) { result = binder.Name; return true; } } 

En este caso, cada vez que intente acceder a una propiedad (con cualquier nombre), el objeto simplemente devuelve el nombre de la propiedad como una cadena.

 dynamic obj = new SampleObject(); Console.WriteLine(obj.SampleProperty); //Prints "SampleProperty". 

Por lo tanto, no tiene nada por lo que reflexionar: este objeto no tiene ninguna propiedad y, al mismo tiempo, todos los nombres de propiedad válidos funcionarán.

Diría que para las implementaciones IDynamicMetaObjectProvider, debe filtrar las implementaciones conocidas donde puede obtener una lista de propiedades, como ExpandoObject, e ignorar (o lanzar una excepción) para el rest.

Requiere Newtonsoft Json.Net

Un poco tarde, pero se me ocurrió esto. Te da solo las teclas y luego puedes usarlas en la dinámica:

 public List GetPropertyKeysForDynamic(dynamic dynamicToGetPropertiesFor) { JObject attributesAsJObject = dynamicToGetPropertiesFor; Dictionary values = attributesAsJObject.ToObject>(); List toReturn = new List(); foreach (string key in values.Keys) { toReturn.Add(key); } return toReturn; } 

Entonces usted simplemente foreach así:

 foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor)) { dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName]; // And dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value } 

Elegir obtener el valor como una cadena o algún otro objeto, o hacer otra dinámica y usar la búsqueda nuevamente.