Получение свойства из его представления - PullRequest
0 голосов
/ 21 декабря 2009

У меня есть некоторые сомнения относительно названия, но я не мог придумать ничего лучшего.

Скажем, у меня есть следующее перечисление

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

Это даст вам представление очто я пытаюсь сделать, но от этого я чувствую себя грязным, как бомж, который только что намочил себя.Это просто нехорошо.

Ответы [ 4 ]

2 голосов
/ 21 декабря 2009
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);
}
2 голосов
/ 21 декабря 2009

Ну, вы можете использовать Reflection для получения свойств. Затем будет найдено свойство на основе его имени.

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

Подробнее см. Метод GetProperties () и возвращенный PropertyInfo тип.

0 голосов
/ 22 декабря 2009

Есть как минимум два способа сделать это:

1. Отражение и информация о недвижимости

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

Вы должны быть осторожны с производительностью, хотя грубый тест для класса с установкой двух свойств и получением всех свойств 10 000 раз занимает 0,06 секунды с отражением и 0,001 секунды, если я пишу это от руки. Таким образом, хит производительности довольно резкий

2.Динамические методы Этот метод более сложный, но производительность того стоит. Динамические методы - это методы, для которых программа генерирует MSIL во время выполнения. Они выполняются во время выполнения, как если бы они были созданы компилятором (поэтому скорость очень хорошая). При использовании этого метода установка и получение 2 свойств в классе 10 000 раз заняла 0,004 секунды (по сравнению с 0,06 секундами с отражением и 0,001 секунды вручную). Ниже приведен код для генерации массива делегатов для методов получения и установки для определенного типа. Генерация динамики может быть дорогостоящей, поэтому вы должны кэшировать делегатов, если вы собираетесь использовать несколько раз (что вы, вероятно, будете).

//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 или setterter или помечены как частные. Это можно легко сделать, взглянув на свойства класса ProperyInfo и создавая делегатов только в случае необходимости

0 голосов
/ 21 декабря 2009

Является ли перечисление и связанные свойства динамическими? Если они есть, вы захотите использовать отражение. В противном случае вы могли бы сделать простое утверждение if-then.

...