2010-11-27 51 views
3

这个代码看看请:从一个普通的对象获取属性在C#

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”我应该得到我的entitiy像.FirstName或属性。姓。我不知道数据对象是IEnumerable还是IOrder等......它必须是通用的!

我怎样才能得到真正的属性表单项?只有反思?

+0

为什么**必须是通用的? – Oded 2010-11-27 17:25:28

+0

我认为它比公共无效BindElements(对象数据对象)更好,因为我必须做演员... – Elisabeth 2010-11-27 17:49:31

回答

6

Oded is right,它似乎(对他或我)没有任何意义,试图使此方法通用。您正试图将其功能实际上特定于某些类型的方法泛化。

现在,那说,看起来批量的功能是独立于你想访问的这个属性。那么,为什么不把它拆分成两个部分:即可以泛型化,而哪些不能:

事情是这样的:

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

如果添加一个constraint的泛型类型(说它实现IPerson接口),您可以使用该接口上定义的任何方法:

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

如果IPerson定义FirstNameLastName peroperties,你可以用它们与T

请参阅generic constraints不同类型的链接。

+0

击败我吧。我的答案几乎完全一样。 – siride 2010-11-27 17:01:57

+0

@Oded抱歉混淆它不应该意味着......是一个IEnumerable它应该意味着ICustomer或IOrder等......但你已经得到它...问题是我不能把IPerson放在那里,因为这会破坏通用该方法的功能!暴露公共BindElements方法的UserControl的用户正在传递一个List 或IEnumerable ,并且T可能是IPerson或ICustomer或IOrder,你明白了吗? – Elisabeth 2010-11-27 17:18:31

3

添加到丹的回答,Func<T, TProperty> selector只是说selector是针对发生在T类型的参数,并且有一个TProperty返回类型的方法的标识符。所以,可能被传递到BindElements作为第二个参数是,例如一个有效的方法,

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

在这种情况下,TProperty将是一个stringTIPerson。然后,您可以拨打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为要支持的每种类型(即ICustomerIOrder)。