Как мне написать метод, который может выводить данные из любого класса с использованием обобщений? - PullRequest
3 голосов
/ 02 августа 2009

Я пытаюсь написать собственный метод для заполнения элемента управления ListView с помощью Generics:

    private void BindDataToListView(List<T> containerItems)
    {
        this.View = View.Details;
        this.GridLines = true;
        this.FullRowSelect = true;

        if (this.Items.Count > 0)
            this.Items.Clear();

        this.BeginUpdate();

        int i = 0;
        foreach (T item in containerItems)
        {
            // do something
        }

        this.EndUpdate();
    }

Параметр containerItems может иметь много элементов, поскольку я использую обобщенные элементы.Но я застреваю в цикле foreach.Как получить доступ к значениям в containerItems?

Нужно ли использовать отражение для каждого экземпляра T в цикле foreach?Я думаю, что я делаю, чтобы получить имя свойства.Но как только я получу имя свойства типа T, как мне получить значение?

Ответы [ 6 ]

2 голосов
/ 03 августа 2009

Наиболее распространенный способ сделать это (с winforms) - через TypeDescriptor; это позволяет вам использовать вещи DataTable так же, как классы; «полный» шаблон является довольно сложным (и включает проверку IListSource, ITypedList и т. д .; однако короткая версия такова; чтобы получить доступные свойства:

PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));

Чтобы получить именованное свойство:

PropertDescriptor prop = props[propName];

Чтобы получить значение для экземпляра (sourceObject):

object val = prop.GetValue(sourceObject);

Чтобы отобразить значение в виде строки (используя назначенный преобразователь):

string s = prop.Converter.ConvertToString(val);
2 голосов
/ 02 августа 2009

Вы можете ограничить T интерфейсом и использовать этот интерфейс в итерации.

1 голос
/ 02 августа 2009

Что представляет собой Т?
Как и сейчас, это универсальный тип, и он может быть ... любым.

Итак, я бы создал интерфейс IListViewBindable или что-то в этом роде. Этот интерфейс может иметь метод 'CreateListViewItem', например.

Затем я бы изменил метод, чтобы к вашему параметру типа T было применено ограничение, сказав, что T должен реализовать IListViewBindable, например:

public void BindDataToListView<T>( List<T> containerItems ) where T : IListViewBindable
{}

В вашем методе BindDataToListView вы можете сделать следующее:

foreach( T item in containerItems )
{
    this.Items.Add (item.CreateListViewItem());
}
0 голосов
/ 03 августа 2009

ObjectListView использует отражение, чтобы сделать именно то, что вы пытаетесь сделать: заполнить ListView, используя отражение. Вы можете избавить себя от многих проблем, используя его. Он уже решил все сложные проблемы, с которыми вы столкнетесь на этом пути.

Если вы действительно, действительно хотите сделать это сами, ответ Марка (конечно) совершенно верен.

0 голосов
/ 02 августа 2009

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

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

object o;
PropertyInfo info = o.GetType().GetProperty().GetProperty("NameOfPropertyIWant");

и вы можете получить значение через

object value = info.GetValue(o, null);

Теперь, если вы собираетесь получать доступ к одноименному свойству на объектах различных типов, вам следует рассмотреть возможность добавления интерфейса

public interface IHasThePropertyIWant {
    object NameOfPropertyIWant { get; }
}

Тогда вы можете применить это с помощью

void BindDataToListView(List<T> containerItems) where T : IHasThePropertyIWant

и используйте его в таком виде

foreach (T item in containerItems) {
    object o = item.NameOfPropertyIWant;
    // do something with o
}  
0 голосов
/ 02 августа 2009

Если элементы в списке имеют полностью неограниченный тип, то вы можете рассматривать их как просто тип object. Вы звоните GetType(), чтобы узнать тип объекта. После этого вы можете вызвать GetProperties(), чтобы получить массив PropertyInfo объектов. И на тех, которые вы можете позвонить GetValue(), чтобы получить значение свойства.

Если вы уже знаете название свойства, просто позвоните GetProperty(), чтобы получить его:

string valueAsString = item.GetType().GetProperty("Something")
                         .GetValue(item, null).ToString();
...