【问题标题】:C# Using the Dynamic keyword to access properties via strings without reflectionC# 使用 Dynamic 关键字通过字符串访问属性而无需反射
【发布时间】:2011-02-16 12:44:28
【问题描述】:

我想写一些类似下面的东西:

//  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
}

我想知道是否有一种简单的方法可以在不使用反射 [.GetProperty(...).GetValue(...,...)] 的情况下使用新的 C# 4.0 关键字:dynamic。

似乎有某种方式,......我只是不确定确切的机制,并且无法找到合适的资源来将所有部分放在一起。

想法?

[编辑] 看起来有一个名为“Clay”的包以某种方式实现了这种类型的功能。 Clay on CodePlex
Scott Hanselman on the Subject

【问题讨论】:

    标签: c# dynamic dynamic-keyword


    【解决方案1】:

    这是可以做到的。你只需要在DynamicObject 上覆盖TryGetIndex。我需要类似的东西来调用一个类型的静态成员,但希望你能明白。请注意,这目前不适用于具有泛型类型参数的方法或重载的方法,从而限制了它的实用性:

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

    【讨论】:

    • 哇,真的很酷的解决方案,我正在寻找这个确切的东西!
    【解决方案2】:

    没有。 C# 中的dynamic 不提供该功能。用你的两个例子:

    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
    

    您可以编写与dynamic 提供的相同代码,但是这比仅使用反射要困难得多。使用反射(根据您的示例),或者如果您需要优化它,您可以选择通过Expression 或Delegate.CreateDelegate 将其包装在委托中。

    【讨论】:

    • 不这么认为,但值得一问!绝对是我从 PHP 中错过的一个功能。当然,至少有 are 方法可以做到这一点,只是认为如果可以通过 Indexer 访问动态对象会很好。 :) - 马修
    【解决方案3】:

    可通过 nuget 获得的开源框架 Impromptu-interface 封装了 dynamic 将以完全动态的方式生成的代码。它不如使用动态关键字快,而是faster than reflection。

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

    【讨论】:

      猜你喜欢
      • 2010-11-08
      • 1970-01-01
      • 2011-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 2010-11-02
      相关资源
      最近更新 更多