List<T> и рефлексия
От: Андрей Россия  
Дата: 30.11.09 10:34
Оценка:
Всем доброго времени суток!

Как через механизмы рефелексии получить доступ к типу, хранящемуся в List<T>?

public struct Info
{
  [Attribute1(100),
   Attribute2("aaa")]
  public PropertyA { get; set; }
  [Attribute1(150),
   Attribute2("bbb")]
  public PropertyB { get; set; }
}

// где-то дальше в коде (про структуру Info здесь ничего неизвестно)
// известно лишь, что DataSource реально представляет из себя список List<T>
// и известны имена свойств "PropertyA" и "PropertyB"
// и здесь нужно добраться до атрибутов этих свойств
//
DataSource ...


03.12.09 08:54: Перенесено модератором из '.NET' — TK
Re: List<T> и рефлексия
От: samius Япония http://sams-tricks.blogspot.com
Дата: 30.11.09 10:43
Оценка: +1
Здравствуйте, Андрей, Вы писали:

А>Всем доброго времени суток!


А>Как через механизмы рефелексии получить доступ к типу, хранящемуся в List<T>?


typeof(mylist).GetGenericArguments()
Re[2]: List<T> и рефлексия
От: Андрей Россия  
Дата: 30.11.09 11:11
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Андрей, Вы писали:


А>>Всем доброго времени суток!


А>>Как через механизмы рефелексии получить доступ к типу, хранящемуся в List<T>?


S>typeof(mylist).GetGenericArguments()


это, конечно, сработало

но дело в том, что мне приходит List<object>, а реально в этом листе сидят структуры, подобные вышеописанным
и естественно, что GetGenericArguments() возвращает мне object

как откастить этот object к реальному типу и получить свойства?
Re[3]: List<T> и рефлексия
От: Пельмешко Россия blog
Дата: 30.11.09 11:14
Оценка:
Здравствуйте, Андрей, Вы писали:

А>это, конечно, сработало


А>но дело в том, что мне приходит List<object>, а реально в этом листе сидят структуры, подобные вышеописанным

А>и естественно, что GetGenericArguments() возвращает мне object

А>как откастить этот object к реальному типу и получить свойства?


Тогда object — и есть реальный тип элементов списка
Может пересоздать список, приведя каждый элемент к нужному типу?
myNeList = myList.Cast<Info>().ToList();
Re[3]: List<T> и рефлексия
От: samius Япония http://sams-tricks.blogspot.com
Дата: 30.11.09 11:19
Оценка:
Здравствуйте, Андрей, Вы писали:

А>Здравствуйте, samius, Вы писали:


S>>Здравствуйте, Андрей, Вы писали:


S>>typeof(mylist).GetGenericArguments()


А>это, конечно, сработало


А>но дело в том, что мне приходит List<object>, а реально в этом листе сидят структуры, подобные вышеописанным

А>и естественно, что GetGenericArguments() возвращает мне object

А>как откастить этот object к реальному типу и получить свойства?


Подобные вышеописанным, или в точности вышеописанные?

Если в точности, то можно воспользоваться оператором приведения типа без рефлексии. Если подобные — у каждого элемента вызывать метод GetType() и дальше по обстоятельствам.
Re[4]: List<T> и рефлексия
От: Андрей Россия  
Дата: 30.11.09 11:26
Оценка:
Здравствуйте, Пельмешко, Вы писали:

П>Здравствуйте, Андрей, Вы писали:


А>>это, конечно, сработало


А>>но дело в том, что мне приходит List<object>, а реально в этом листе сидят структуры, подобные вышеописанным

А>>и естественно, что GetGenericArguments() возвращает мне object

А>>как откастить этот object к реальному типу и получить свойства?


П>Тогда object — и есть реальный тип элементов списка

П>Может пересоздать список, приведя каждый элемент к нужному типу?
П>
П>myNeList = myList.Cast<Info>().ToList();
П>


хм, таких структур не одна, к сожалению
поэтому пересоздать список в данном случае невозможно

списки я получаю через методы интерфейса, а они возвращают List<object>
и там, где я их получаю, мне реально сидящий тип не особо и нужен
мне нужно только получить у свойств (а их имена известны) атрибуты с тоже известными именами

интересно, а как DataGridView работает в данном случае?
он вполне нормально достает из моих списков List<object> нужные ему атрибуты (в частности, DisplayNameAttribute для каждого поля структуры)
Re[5]: List<T> и рефлексия
От: Пельмешко Россия blog
Дата: 30.11.09 11:34
Оценка:
Здравствуйте, Андрей, Вы писали:

А>списки я получаю через методы интерфейса, а они возвращают List<object>

А>и там, где я их получаю, мне реально сидящий тип не особо и нужен
А>мне нужно только получить у свойств (а их имена известны) атрибуты с тоже известными именами

А>интересно, а как DataGridView работает в данном случае?

А>он вполне нормально достает из моих списков List<object> нужные ему атрибуты (в частности, DisplayNameAttribute для каждого поля структуры)

Через всякие TypeDescriptor'ы оно работает, а оные через рефлексию...

И Вам тоже так придётся, как написали выше, .GetType() у каждого элемента, потом .GetProperties(), .GetCustomAttributes() и в бой...
Re[6]: List<T> и рефлексия
От: Андрей Россия  
Дата: 30.11.09 11:43
Оценка:
Здравствуйте, Пельмешко, Вы писали:

skip

П>Через всякие TypeDescriptor'ы оно работает, а оные через рефлексию...


а можно поподробнее с этого места?

П>И Вам тоже так придётся, как написали выше, .GetType() у каждого элемента, потом .GetProperties(), .GetCustomAttributes() и в бой...


не выходит каменный цветок с List<object> — мне возвращается System.Object и все, дальше оно не идет
само собой, что у этого object нет ни свойств, ни атрибутов
Re[4]: List<T> и рефлексия
От: Андрей Россия  
Дата: 30.11.09 11:59
Оценка:
Здравствуйте, samius, Вы писали:

skip

S>Подобные вышеописанным, или в точности вышеописанные?


S>Если в точности, то можно воспользоваться оператором приведения типа без рефлексии. Если подобные — у каждого элемента вызывать метод GetType() и дальше по обстоятельствам.


оператор приведения типа мне не подходит — я не знаю в этом месте реальных типов
а про GetType для каждого элемента — непонятно

List<Object>.GetGenericArguments() возвращает массив из одного элемента typeof(object).
что с ним дальше делать — абсолютно не представляю, получать от него новый Type — бесполезно, пытаться получить Properties или создать TypeDescriptor — тоже
Re[7]: List<T> и рефлексия
От: Пельмешко Россия blog
Дата: 30.11.09 12:16
Оценка:
Здравствуйте, Андрей, Вы писали:

П>>И Вам тоже так придётся, как написали выше, .GetType() у каждого элемента, потом .GetProperties(), .GetCustomAttributes() и в бой...


А>не выходит каменный цветок с List<object> — мне возвращается System.Object и все, дальше оно не идет

А>само собой, что у этого object нет ни свойств, ни атрибутов

По-моему всё что Вам нужно — рефлексия, вот кривой пример как прочитать все свойства, отмеченные [ObsoleteAttribute]:
class Foo
{
  [Obsolete]
  public int Value { get; set; }
}

class Bar
{
  [Obsolete]
  public string Hello { get; set; }
}

class Program
{
  private static void Main()
  {
    var list = new List<object> {
      new Foo { Value = 45 },
      new Bar { Hello = "hello!" }
    };

    foreach (object obj in list)
    {
      var marketProperties = obj
        .GetType()
        .GetProperties()
        .Where(prop =>
          Attribute.IsDefined(prop, typeof(ObsoleteAttribute)));

      foreach(var prop in marketProperties)
      {
        Console.WriteLine(prop.GetValue(obj, null));
      }
    }
  }
}

Вполне возможно, что это проще решается через TypeDescriptor, но я не разбирался с ним совсем...
Re[5]: List<T> и рефлексия
От: samius Япония http://sams-tricks.blogspot.com
Дата: 30.11.09 12:18
Оценка: 12 (1)
Здравствуйте, Андрей, Вы писали:

А>Здравствуйте, samius, Вы писали:


А>skip


S>>Подобные вышеописанным, или в точности вышеописанные?


S>>Если в точности, то можно воспользоваться оператором приведения типа без рефлексии. Если подобные — у каждого элемента вызывать метод GetType() и дальше по обстоятельствам.


А>оператор приведения типа мне не подходит — я не знаю в этом месте реальных типов

А>а про GetType для каждого элемента — непонятно

Вот, Пельмешко развернуто ответил выше.
Re[8]: List<T> и рефлексия
От: Андрей Россия  
Дата: 30.11.09 12:29
Оценка:
Здравствуйте, Пельмешко, Вы писали:

skip


ок, я понял

но вот какая засада: а если в коллекции нет элементов?

то есть что-то типа:

class Foo
{
  [Obsolete]
  public int Value {get;set;}
}

class Program
{
  private static void Main()
  {
    var list = new List<Foo>();

    // здесь я этот list куда-то передаю
    // там, где его принимают, про тип Foo не имеют понятия
    // все, что о нем известно - что у него есть свойство с именем Value и у этого свойства возможно есть атрибут Obsolete
  }
}


меня как раз этот случай и интересует — когда на вход подается пустая коллекция

чтобы было понятней: я пытаюсь настроить ширину полей (а также некоторые другие аспекты внешнего вида) DataGridView через атрибуты полей коллекции привязанной к DataSource
типов этих коллекций может быть довольно много (то есть List<Structure1>, List<Structure2> и т.д.), и я не знаю, с какой структурой я работаю в данный момент

если эта структура имеет элементы — никаких проблем не возникает
через первый элемент коллекции я получаю нужные мне атрибуты

проблема возникает, когда на вход приходит пустая коллекция — в этом случае я никак не могу узнать типы полей, так как нет текущего элемента
Re[9]: List<T> и рефлексия
От: Пельмешко Россия blog
Дата: 30.11.09 12:40
Оценка: 10 (1)
Здравствуйте, Андрей, Вы писали:

А>Здравствуйте, Пельмешко, Вы писали:


А>skip



А>ок, я понял


А>но вот какая засада: а если в коллекции нет элементов?


А>меня как раз этот случай и интересует — когда на вход подается пустая коллекция


А>чтобы было понятней: я пытаюсь настроить ширину полей (а также некоторые другие аспекты внешнего вида) DataGridView через атрибуты полей коллекции привязанной к DataSource

А>типов этих коллекций может быть довольно много (то есть List<Structure1>, List<Structure2> и т.д.), и я не знаю, с какой структурой я работаю в данный момент

А>если эта структура имеет элементы — никаких проблем не возникает

А>через первый элемент коллекции я получаю нужные мне атрибуты

А>проблема возникает, когда на вход приходит пустая коллекция — в этом случае я никак не могу узнать типы полей, так как нет текущего элемента


Тогда возвращаемся к началу, делаете раз:
var type = grid.DataSource.GetType();

А потом исследуете тип, которым параметризован List<T>:
// сразу предупреждаю, не будет работать с наследниками List<>
if (type.IsGenericType &&
    type.GetGenericDefinition() == typeof(List<>))
{
  var elementType = type.GetGenericArguments()[0];
  elementType.GetProperties() ....
}

Вообще, наверное, надо не на List<T> проверять, а ниже, вроде биндить можно ко всему, начиная с IEnumerable<T>...
Re[10]: List<T> и рефлексия
От: Пельмешко Россия blog
Дата: 30.11.09 12:42
Оценка: 12 (1)
Здравствуйте, Пельмешко, Вы писали:

П>Вообще, наверное, надо не на List<T> проверять, а ниже, вроде биндить можно ко всему, начиная с IEnumerable<T>...


Простите, вру, там начиная с IList...
Re[9]: List<T> и рефлексия
От: Андрей Россия  
Дата: 30.11.09 12:44
Оценка:
Здравствуйте, Андрей, Вы писали:

skip

хотя наврал, в последнем случае работает как раз-таки нормально
в общем, разобрался

получилось не очень красиво, но работает
Re[6]: List<T> и рефлексия
От: samius Япония http://sams-tricks.blogspot.com
Дата: 30.11.09 12:46
Оценка: :)
Здравствуйте, samius, Вы писали:

S>Вот, Пельмешко развернуто ответил выше.


Пельмешко отвечал, ему и оценку!
Re[7]: List<T> и рефлексия
От: Андрей Россия  
Дата: 30.11.09 12:54
Оценка:
Здравствуйте, samius, Вы писали:

skip

обоим поставил — мне не жалко за здравые идеи

вообще интересная ситуация получается: если я в DataGridView в качестве DataSource задаю object (а на самом деле List<myStructure>), то все получается как надо: рефлексия работает на ура
а вот если List<object> (где на самом деле вместо object находятся экземпляры myStructure), то все встает раком

при этом сам DataGridView без проблем съедает все варианты
раскопать бы код в DataGridView, который разбирает атрибуты полей

ладно, тему можно считать закрытой

всем спасибо
Re[8]: List<T> и рефлексия
От: Пельмешко Россия blog
Дата: 30.11.09 13:03
Оценка:
Здравствуйте, Андрей, Вы писали:

А>Здравствуйте, samius, Вы писали:


А>skip


А>обоим поставил — мне не жалко за здравые идеи


А>вообще интересная ситуация получается: если я в DataGridView в качестве DataSource задаю object (а на самом деле List<myStructure>), то все получается как надо: рефлексия работает на ура

А>а вот если List<object> (где на самом деле вместо object находятся экземпляры myStructure), то все встает раком

А>при этом сам DataGridView без проблем съедает все варианты


Наверное потому что оно получает List<object> с элементами, и исследует их... Без элементов в List<object> DataGrid не сможет ничего исследовать...
Вы можете скомбинировать оба варианта: когда type == typeof(List<object>) заглядывать внутрь листа и поглядеть какого типа элементы...
Re: List<T> и рефлексия
От: sto Украина http://overstore.codeplex.com
Дата: 02.12.09 11:32
Оценка: 34 (2) +1
Здравствуйте, Андрей, Вы писали:

А>Всем доброго времени суток!


А>Как через механизмы рефелексии получить доступ к типу, хранящемуся в List<T>?


А>
А>public struct Info
А>{
А>  [Attribute1(100),
А>   Attribute2("aaa")]
А>  public PropertyA { get; set; }
А>  [Attribute1(150),
А>   Attribute2("bbb")]
А>  public PropertyB { get; set; }
А>}

А>// где-то дальше в коде (про структуру Info здесь ничего неизвестно)
А>// известно лишь, что DataSource реально представляет из себя список List<T>
А>// и известны имена свойств "PropertyA" и "PropertyB"
А>// и здесь нужно добраться до атрибутов этих свойств
А>//
А>DataSource ...
А>


Попробуйте ListBindingHelper, если вас не пугает перспектива подключения сборки System.Windows.Forms.
Через него собственно все контролы и работают.
There is no such thing as the perfect design.
Re[2]: List<T> и рефлексия
От: Андрей Россия  
Дата: 02.12.09 11:45
Оценка:
Здравствуйте, sto, Вы писали:

skip

sto>Попробуйте ListBindingHelper, если вас не пугает перспектива подключения сборки System.Windows.Forms.

sto>Через него собственно все контролы и работают.

о, похоже как раз то, что надо
спасибо большое
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.