2010-11-27 59 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)。