从属性的表示中获取属性

发布于 2024-08-15 13:09:12 字数 669 浏览 3 评论 0原文

我对这个标题有一些疑问,但我想不出更好的。

假设我有以下枚举

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

这会让您了解我正在尝试的内容想做,但尝试让我感觉很脏,就像一个刚刚尿湿了自己的流浪汉一样。就是感觉不太对劲。

I have some doubt about the title, but I couldn't come up with anything better.

Say I have the following enum

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

And a class that looks this

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

Now somewhere along the line I need to iterate over the enumeration and use each item in it to get the property, like so:

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

This would give you an idea of what I'm trying to do, but trying it makes me feel dirty like a bum who just wet himself. It just doesn't feel right.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

眼眸里的那抹悲凉 2024-08-22 13:09:12

那么您可以使用反射来检索属性。然后,这将根据名称找到该属性。

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

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

Well you could use Reflection to retrieve the properties. This will then locate the property based on its name.

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

For more see GetProperties() method & the returned PropertyInfo type.

淡笑忘祈一世凡恋 2024-08-22 13:09:12
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);
}
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);
}
节枝 2024-08-22 13:09:12

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

Is the enumeration and associated properties dynamic? If they are you will want to use reflection. Otherwise, you could do a simple if-then statement.

剧终人散尽 2024-08-22 13:09:12

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

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 秒)。下面是为某种类型的 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 或标记为 private 的属性。通过查看 ProperyInfo 类的属性并仅在适当的情况下创建委托,可以轻松完成此操作

There are at least two ways of doing this:

1.Reflection and 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 });
}

You should be careful with regard to performance though, just a rough test for a class with two properties setting and getting all the properties 10k times takes 0.06 seconds with reflection and 0.001 seconds if I write it by hand. So the performance hit is pretty drastic

2.Dynamic Methods
This method is more complicated but the performance is well worth it. Dynamic methods are methods which the program emits MSIL for at runtime. They get executed by the runtime as if they were created by the compiler (so the speed is very good). Using this method setting and getting 2 properties on a class 10k times took 0.004 seconds (compared to 0.06 seconds with reflection and 0.001 second by hand). Bellow is the code to generate an array of delegates for getters and setters for a certain type. Generating the dynamic can be costly so you should cache the delegates if you intend to use the multiple times (which you probably will).

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

Invocation of the dynamic methods:

// 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: The code above does not deal with properties that have no getter or no setter or are marked as private. This could be easily done by looking at the properties of the ProperyInfo Class and only creating the delegates if apropriate

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文