C# Using the Dynamic keyword to access properties via strings without reflection

99封情书 提交于 2019-11-30 12:38:06
João Bragança

It can be done. You just have to override TryGetIndex on DynamicObject. I needed something similar to invoke static members of a type, but hopefully you will get the idea. Mind you this does not currently work on methods with generic type arguments or methods that are overloaded, limiting its utility:

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);

No. dynamic in C# doesn't offer that. With your two examples:

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

You can write the same code that dynamic offers, but it would be a lot harder than just using reflection. Either use reflection (as per your example), or if you need to optimise it you can optionally wrap it in a delegate, via either Expression or Delegate.CreateDelegate.

The opensource framework Impromptu-interface available via nuget encapsulates the code that dynamic would generate in a fully dynamic fashion. It's not as fast as using the dynamic keyword, but is faster than reflection.

foreach(var s in properties) 
{
  //d.s = true; 
  Impromptu.InvokeSet(d, s, true);
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!