2010-05-06 12 views
12

me gustaría escribir algo similar a lo siguiente:C# usando la palabra clave dinámica para acceder a las propiedades a través de cadenas sin reflexión

// I will pass in a number of "properties" specified as strings that I want modified 
string[] properties = new [] { "AllowEdit", "AllowDelete" }; 

// Casting the component I'm using to a dynamic object of some sort ? 
dynamic d = myGridComponent; 

// Iterate over the strings and set the properties 
foreach(var s in properties) 
{ 
    //d.s = true; // 
    //d[s] = true; // this format would be ideal 
} 

Me preguntaba si había una manera fácil de hacer esto sin usar Reflexión [.GetProperty(...).GetValue(...,...) ] usando la nueva palabra clave C# 4.0: dynamic.

Parece que puede haber alguna forma ... No estoy seguro del mecanismo exacto y no he podido encontrar el recurso adecuado para unir todas las piezas.

¿Pensamientos?

[EDIT] Parece que hay un paquete llamado "Clay" que implementa este tipo de funcionalidad de alguna manera. Clay on CodePlex
Scott Hanselman on the Subject

Respuesta

6

Se puede hacer. Solo tiene que anular TryGetIndex en DynamicObject. Necesitaba algo similar para invocar miembros estáticos de un tipo, pero con suerte obtendrá la idea. Cuenta que esto no funciona actualmente en métodos con argumentos de tipo genérico o métodos que están sobrecargados, lo que limita su utilidad:

internal class StaticMembersDynamicWrapper : DynamicObject 
{ 
    private readonly IDictionary<String, MemberInfo> staticMembers = new Dictionary<string, MemberInfo>(); 
    private readonly Type type; 

    public StaticMembersDynamicWrapper(Type type) 
    { 
     this.type = type; 
     type.GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public) 
      .Each(member => staticMembers[member.Name] = member); 
    } 

    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) 
    { 
     var name = indexes[0] as string; 

     MemberInfo member; 

     if (false == staticMembers.TryGetValue(name, out member)) 
     { 
      result = null; 
      return false; 
     } 

     var prop = member as PropertyInfo; 
     if (prop != null) 
     { 
      result = prop.GetValue(null, null); 
      return true; 
     } 
     var method = member as MethodInfo; 
     if (method != null) 
     { 
      var parameterTypes = (from p in method.GetParameters() 
            select p.ParameterType).ToArray(); 
      var delegateType = method.ReturnType != typeof (void) 
          ? Expression.GetFuncType(parameterTypes.Union(new[]{method.ReturnType}).ToArray()) 
          : Expression.GetActionType(parameterTypes); 
      result = Delegate.CreateDelegate(delegateType, method); 
      return true; 
     } 
     result = null; 
     return false; 
    } 
} 

dynamic d = new StaticMembersDynamicWrapper(typeof(string)); 
var result = d["IsNullOrEmpty"](String.Empty); 
+0

¡Solución realmente genial, estaba buscando esto exactamente! –

3

dynamic en C# no ofrece eso. Con sus dos ejemplos:

d.s = true; // this looks for a property or field called "s" 
d[s] = true; // this looks for an indexer that matches the string/bool signature 

Usted puede escribir el mismo código que dynamic ofertas, pero sería mucho más difícil que simplemente usar la reflexión. Use el reflejo (según su ejemplo), o si necesita optimizarlo puede opcionalmente envolverlo en un delegado, ya sea a través de Expression o Delegate.CreateDelegate.

+0

No lo creo, pero vale la pena preguntarlo! Definitivamente, una característica que extraño de PHP ... por supuesto, al menos hay * maneras * de hacerlo, simplemente pensé que sería bueno si se pudiera acceder a los objetos dinámicos a través de Indexer. :) - Matthew –

2

El marco de código abierto Impromptu-interface disponible a través de Nuget encapsula el código que dinámico generaría de forma totalmente dinámica. No es tan rápido como usar la palabra clave dinámica, pero es faster than reflection.

foreach(var s in properties) 
{ 
    //d.s = true; 
    Impromptu.InvokeSet(d, s, true); 
} 
+0

Funcionó muy bien, gracias. –

Cuestiones relacionadas