Получить свойство из универсального объекта в C # - PullRequest
3 голосов
/ 27 ноября 2010

посмотрите на этот код, пожалуйста:

public void BindElements<T>(IEnumerable<T> dataObjects)
{
    Paragraph para = new Paragraph();

    foreach (T item in dataObjects)
    {
        InlineUIContainer uiContainer =
            this.CreateElementContainer(item.FirstName ????? )              
        para.Inlines.Add(uiContainer);
    }                         

    FlowDocument flowDoc = new FlowDocument(para);
    this.Document = flowDoc;
}

Когда я пишу в Visual Studio "item.XXX", я должен получить свойства из моего права, например .FirstName или .LastName.Я не знаю, является ли dataObjects IEnumerable или IOrder и т. Д. ... он должен быть универсальным!

Как я могу получить объект недвижимости?Только с отражением?

Ответы [ 4 ]

7 голосов
/ 27 ноября 2010

Одед прав , не кажется (ему или мне) никакого смысла пытаться сделать этот метод универсальным.Вы пытаетесь обобщить метод, функциональность которого на самом деле специфична для нескольких типов.

Теперь, с другой стороны, кажется, что bulk функции не зависит от этого свойства, к которому вы хотите получить доступ,Так почему бы не разделить его на две части: то, что может быть обобщено, и то, что не может:

Что-то вроде этого:

void BindElements<T, TProperty>(IEnumerable<T> dataObjects,
                                Func<T, TProperty> selector)
{
    Paragraph para = new Paragraph();

    foreach (T item in dataObjects)
    {
       // Notice: by delegating the only type-specific aspect of this method
       // (the property) to (fittingly enough) a delegate, we are able to 
       // package MOST of the code in a reusable form.
       var property = selector(item);

       InlineUIContainer uiContainer = this.CreateElementContainer(property)
       para.Inlines.Add(uiContainer);
    }

    FlowDocument flowDoc = new FlowDocument(para);
    this.Document = flowDoc;
}

Тогда ваши перегрузки имеют дело с конкретными типами, например, IPerson, может повторно использовать этот код (который, я подозреваю, может быть тем, кем вы были в конце концов - повторное использование кода):

public void BindPeople(IEnumerable<IPerson> people)
{
    BindElements(people, p => p.FirstName);
}

... затем для IOrder:

public void BindOrders(IEnumerable<IOrder> orders)
{
    BindElements(orders, o => p.OrderNumber);
}

... и т. Д.

4 голосов
/ 27 ноября 2010

Если вы добавите ограничение к универсальному типу (скажем, оно должно реализовывать интерфейс IPerson), вы можете использовать любые методы, определенные в интерфейсе:

public void BindElements<T>(IEnumerable<T> dataObjects) where T : IPerson

Если IPerson определяет FirstName и LastName разрешений, вы можете использовать их с T.

См. Ссылку для различных типов общих ограничений возможных.

3 голосов
/ 28 ноября 2010

Добавляя к ответу Дэна, Func<T, TProperty> selector просто говорит, что selector является идентификатором метода, который принимает параметр типа T и имеет тип возврата TProperty.Таким образом, допустимый метод, который может быть передан в BindElements в качестве второго параметра, будет, например,

string CreatePersonElement(IPerson person) {
    return string.Format("{0} {1}", person.FirstName, person.LastName);
}

. В этом случае TProperty будет string, а T будетIPerson.Затем вы можете позвонить BindElements следующим образом:

BindElements(myPersonCollection,CreatePersonElement);

, где myPersonCollection может быть просто тем, на что вы ссылались List<T>.Затем для перехода к циклу foreach

foreach (T item in dataObjects) {
   // Notice: by delegating the only type-specific aspect of this method
   // (the property) to (fittingly enough) a delegate, we are able to 
   // package MOST of the code in a reusable form.
   var property = selector(item);

   InlineUIContainer uiContainer = this.CreateElementContainer(property)
   para.Inlines.Add(uiContainer);
}

property устанавливается объект типа TProperty, который в случае CreatePersonElement является string.Если string не работает для вас, просто измените тип возвращаемого значения метода на тот, который CreateElementContainer принимает в качестве его параметра.

Затем у вас будет один из этих методов для передачи ввторой параметр для BindElements для каждого типа, который вы хотите поддерживать (например, ICustomer, IOrder).

0 голосов
/ 27 ноября 2010

Я бы прочитал http://msdn.microsoft.com/en-us/library/d5x73970.aspx и снова подумал бы об ответе Одеда.

...