【问题标题】:Getting a property from an representation of it从它的表示中获取属性
【发布时间】:2010-12-28 18:15:37
【问题描述】:

我对标题有些怀疑,但我想不出更好的。

假设我有以下枚举

public enum ClassProperties
{
     Primary = 0,
     Secondary = 1,
}

还有一个看起来像这样的类

public class Test
{
    Primary { get { return _primary; }}
    Secondary { get { return _secondary; }}
    // more irrelevant properties
}

现在我需要遍历枚举并使用其中的每个项目来获取属性,如下所示:

foreach(ClassProperties myProp = Enum.GetValues(typeof(ClassProperties)))
{
    Test t = new Test();
    t.myProp // <- this is what I'm after
    // so if myProp equals Primary,
    // t.Primary is called...
}

这会让你知道我正在尝试做什么,但尝试它会让我觉得自己像一个刚刚弄湿自己的流浪汉一样肮脏。就是感觉不对。

【问题讨论】:

  • 反射不是更好吗?
  • 不确定您在此处寻找什么。您能否解释一下您要解决的问题,而不是建议的解决方案?
  • 它们都是同一类型吗?如果是这样,一个 Dictionary 可能适合。
  • 您的Test 类定义不正确,未指定属性类型。此外,调用属性是不可能的;您可能需要更新您的代码示例以添加影响。
  • 这只是一个或多或少伪代码的说明。

标签: c# string properties types enums


【解决方案1】:

你可以使用反射来检索属性。然后,这将根据其名称定位该属性。

Test t = new Test();
Type testType = t.GetType();
PropertyInfo[] properties = testType.GetProperties();

有关更多信息,请参阅 GetProperties() method 和返回的 PropertyInfo 类型。

【讨论】:

  • 当你进入它时,反射是相当直接的。它相当强大,尽管您确实会受到轻微的性能影响。在大多数情况下,这应该不是问题。
  • 在这个应用程序中性能不是问题。这是我们用于 dns 服务器的一个小工具。纯属内部。
【解决方案2】:

枚举和相关属性是动态的吗?如果是,您将需要使用反射。否则,你可以做一个简单的 if-then 语句。

【讨论】:

    【解决方案3】:
    foreach(ClassProperties myProp in Enum.GetValues(typeof(ClassProperties)))
    {
        Test t = new Test();
        PropertyInfo prop = typeof(Test).GetProperty(myProp.ToString());
        // Get
        object value = prop.GetValue(t, null);
        // Set
        prop.SetValue(t, newValue, null);
    }
    

    【讨论】:

      【解决方案4】:

      至少有两种方法可以做到这一点:

      1.Reflection和PropertyInfo

      var obj = new TestClass();
      var allProps = typeof(TestClass).GetProperties();
      foreach (var prop in allProps)
      {
          // Get propertie value
          object propValue = prop.GetGetMethod().Invoke(obj, null);
          //Set propertie value
          prop.GetSetMethod().Invoke(obj, new object[] { propValue });
      }
      

      您应该注意性能,只是对具有两个属性设置的类进行粗略测试,并且将所有属性获取 10k 次需要 0.06 秒(反射)和 0.001 秒(如果我手动编写)。所以对性能的影响是相当大的

      2.动态方法 这种方法比较复杂,但性能非常值得。动态方法是程序在运行时为其发出 MSIL 的方法。它们由运行时执行,就好像它们是由编译器创建的一样(因此速度非常好)。使用此方法设置并在类上获取 2 个属性 10k 次需要 0.004 秒(相比之下,反射为 0.06 秒,手动为 0.001 秒)。 Bellow 是为特定类型的 getter 和 setter 生成委托数组的代码。生成动态可能会很昂贵,因此如果您打算多次使用(您可能会这样做),您应该缓存委托。

      //Container for getters and setters of a property
      public class MyProp
      {
          public string PropName { get; set; }
          public Func<object,object> Getter{get;set;}
          public Action<object,object> Setter{get;set;}
      }
      
      public static MyProp[] CreatePropertyDelagates (Type type)
      {
            var allProps = type.GetProperties();
            var props = new MyProp[allProps.Length];
      
            for(int i =0;i<allProps.Length;i++)
            {
                  var prop = allProps[i];
                  // Getter dynamic method the signature would be :
                  // object Get(object thisReference)
                  // { return ((TestClass)thisReference).Prop; }
      
                  DynamicMethod dmGet = new DynamicMethod("Get", typeof(object), new Type[] { typeof(object), });
                  ILGenerator ilGet = dmGet.GetILGenerator();
                  // Load first argument to the stack
                  ilGet.Emit(OpCodes.Ldarg_0);
                  // Cast the object on the stack to the apropriate type
                  ilGet.Emit(OpCodes.Castclass, type);
                  // Call the getter method passing the object on the stack as the this reference
                  ilGet.Emit(OpCodes.Callvirt, prop.GetGetMethod());
                  // If the property type is a value type (int/DateTime/..) box the value so we can return it
                  if (prop.PropertyType.IsValueType)
                  {
                        ilGet.Emit(OpCodes.Box, prop.PropertyType);
                  }
                  // Return from the method
                  ilGet.Emit(OpCodes.Ret);
      
      
                  // Setter dynamic method the signature would be :
                  // object Set(object thisReference, object propValue)
                  // { return ((TestClass)thisReference).Prop = (PropType)propValue; }
      
                  DynamicMethod dmSet = new DynamicMethod("Set", typeof(void), new Type[] { typeof(object), typeof(object) });
                  ILGenerator ilSet = dmSet.GetILGenerator();
                  // Load first argument to the stack and cast it
                  ilSet.Emit(OpCodes.Ldarg_0);
                  ilSet.Emit(OpCodes.Castclass, type);
      
                  // Load secons argument to the stack and cast it or unbox it
                  ilSet.Emit(OpCodes.Ldarg_1);
                  if (prop.PropertyType.IsValueType)
                  {
                        ilSet.Emit(OpCodes.Unbox_Any,prop.PropertyType);
                  }
                  else
                  {
                        ilSet.Emit(OpCodes.Castclass, prop.PropertyType);
                  }
                  // Call Setter method and return 
                  ilSet.Emit(OpCodes.Callvirt, prop.GetSetMethod());
                  ilSet.Emit(OpCodes.Ret);
      
                  // Create the delegates for invoking the dynamic methods and add the to an array for later use
                  props[i] =  new MyProp()
                  {
                        PropName = prop.Name,
                        Setter = (Action<object, object>)dmSet.CreateDelegate(typeof(Action<object, object>)),
                        Getter = (Func<object, object>)dmGet.CreateDelegate(typeof(Func<object, object>)),
                  };
      
            }
            return props;
      }
      

      动态方法的调用:

      // Should be cahced for further use 
      var testClassProps = CreatePropertyDelagates(typeof(TestClass));
      
      var obj = new TestClass();
      foreach (var p in testClassProps)
      {
            var propValue = p.Getter(obj);
            p.Setter(obj,propValue);
      }
      

      Obs:上面的代码不处理没有 getter 或没有 setter 或标记为私有的属性。这可以通过查看 ProperyInfo 类的属性并仅在适当的情况下创建委托来轻松完成

      【讨论】:

        猜你喜欢
        • 2013-10-31
        • 1970-01-01
        • 2014-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-16
        相关资源
        最近更新 更多