Подтвердить что ты не робот

Получить список <T> значений с поздним связыванием

У меня есть переменная List<T>, где T не известно во время компиляции. Мне нужно получить доступ к свойству value по типу T, как этот

foreach(var item in items) // items is List<T>
{
    item.value // this won't compile because T is unknown 
}

Я знаю, что <T> в моем случае будет иметь свойство value. Как я могу получить к нему доступ?

4b9b3361

Ответ 1

Если вы KNOW, что каждый T имеет VALUE, вы можете использовать dynamic вместо var

foreach(dynamic item in items) //items is List<T>
{
    item.VALUE
}

Ответ 2

Как уже было сказано, правильным способом является создание интерфейса, реализующего Value prop.

Однако вы прокомментировали, что у вас нет контроля над классами, вам нужно будет сделать это по-другому.

Одним из способов было бы отражение, я предполагаю, что ваше имя свойства VALUE (с учетом регистра)

PropertyInfo pi = typeof(T).GetProperty("VALUE");
object value = pi == null ? null pi.GetValue(item,null);

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

В качестве альтернативы вы можете использовать статический общий вспомогательный класс с полем и вспомогательный метод.

 public static class ValueHelper<T> {
     public static Func<T,object> ValueFunction;

     public static object GetValue(T item) {
        var function = ValueFunction;
        return function == null ? null : function(item);
     }

     }
 }

Затем где-то в вашем коде, где вы знаете T, например, вы хотите настроить MyClass

  ValueHelper<MyClass>.ValueFunction = x => x.Value;

Затем ваш код списка станет

foreach(var item in items)
{
    value = ValueHelper<T>.GetValue(item);
}

Ответ 3

Если у вас есть контроль над классами T, вы можете ввести интерфейс со значением Value и сделать каждый T-класс реализацией этого интерфейса. В этом случае вы можете перечислить такие значения:

    foreach(IMyInterface item in items)
    {
        var someVar = item.VALUE; 
//you know that item does have VALUE property and the type of that property as declared in interface
    }

UPD. Он работает, даже если ваши классы T имеют разные свойства:

interface IMyInterface
{
    string VALUE{get;set;}
}

class A : IMyInterface
{
   public int Aprop{get;set;}
   public string VALUE{get;set;}
}

class B : IMyInterface
{
   public int Bprop{get;set;}
   public string VALUE{get;set;}
}

Ответ 4

Если типы T известны заранее, вы можете сделать это (не лучший подход, но они уже объяснены в других ответах):

foreach(var item in List<T>)
{
  if (item.GetType().Equals(typeof(fooClassA)))
  {
     ret = (item as fooClassA).VALUE_A;
  }
  if (item.GetType().Equals(typeof(fooClassB)))
  {
     ret = (item as fooClassB).VALUE_B;
  }
  ....
}