2010-07-09 106 views
7

是否可以創建一個擴展方法來返回調用擴展方法的實例?C#中的鏈接擴展方法

我想對從ICollection<T>繼承的任何東西有一個擴展方法,返回該對象。就像jQuery總是返回jquery對象一樣。

public static object AddItem<T>(this ICollection<T> collection, T itemToAdd) 
{ 
    collection.Add(itemToAdd); 
    return collection; 
{ 

我想象像上面,但我不知道如何回到父的「此」對象類型,使用的是這樣的:

List<int> myInts = new List<int>().AddItem(5); 

編輯:只是想很明顯,我希望有一個通用的約束解決方案。

回答

13

如果您需要返回的具體類型,可以使用通用約束:

public static TCollection AddItem<TCollection, TElement>(
    this TCollection collection, 
    TElement itemToAdd) 
    where TCollection : ICollection<TElement> 
{ 
    collection.Add(itemToAdd); 
    return collection; 
} 

我測試了這一點,它在VS2010工作。

更新(關於jQuery的):

jQuery的鏈接工作得非常好,因爲JavaScript使用動態類型。 C#4.0支持dynamic,所以你可以這樣做:

public static dynamic AddItem<T>(this ICollection<T> collection, T itemToAdd) 
{ 
    collection.Add(itemToAdd); 
    return collection; 
} 

不過,我建議通用約束版本,因爲它是更加類型安全,更高效,並允許智能感知的返回類型。在更復雜的情況下,通用約束並不總是能夠表達你所需要的;在這些情況下,可以使用dynamic(儘管它不會綁定到其他擴展方法,因此鏈接效果不佳)。

+0

謝謝。起初,我這樣做,但不喜歡2泛型規範。但是,我想到了,因爲類型是TCollection隱含的,你實際上不需要在代碼中指定它。 – 2010-07-09 20:12:17

+0

對。使用它的代碼正是你在你的問題中所擁有的;沒有明確的類型參數是必要的。我也更新了關於jQuery的答案。 – 2010-07-09 20:20:44

4

雖然我沒有VS打開試試這個,這些方針的東西應該工作:

public static TCollection AddItem<TCollection, TItem>(TCollection collection, 
                 TItem itemToAdd) 
where TCollection : ICollection<TItem> 
{ 
    collection.Add(itemToAdd); 
    return collection; 
} 
0

只是返回ICollection<T>,而不是object,一切都應該像你預期它。

+1

不,因爲他將它分配給一個'List '類型的變量。 – 2010-07-09 20:02:06

+1

這是正確的。我錯誤地認爲演員不會工作,但那是ReSharper把紅色的波浪線和更換一些先前的語法之後花了很長時間來更新。 – 2010-07-09 20:04:41

+1

對不起,我錯了,亞當是正確的。 – 2010-07-09 20:06:57

2

你似乎有2倍相互衝突的目標,並把它歸結爲您希望您的擴展方法返回什麼:

  • 調用該擴展方法(集合)
  • 或項目的實例已添加到收藏

從你的使用例子,在這裏引用:

List<int> myInts = new List<int>().AddItem(5); 

你讓它看起來像你想要返回集合。在任何情況下,分配仍然不會沒有科協工作,因爲你的擴展方法需要有ICollection的返回類型,就像這樣:

public static ICollection<T> AddItem<T>(this ICollection<T> collection, T itemToAdd) 
{ 
    collection.Add(itemToAdd); 
    return collection; 
} 

這將允許你這樣做:

List<int> myList = (List<int>) new List<int>().AddItem(5); 

現在,如果您希望返回添加的對象,那麼您仍不應該有返回類型object。你應該充分利用你的泛型類型參數,並返回T,像這樣:

public static T AddItem<T>(this ICollection<T> collection, T itemToAdd) 
{ 
    collection.Add(itemToAdd); 
    return itemToAdd; 
} 

但是,如果你回國加入該項目,你將不能夠像這條產業鏈:

List<int> myList = (List<int>) new List<int>().AddItem(5); 

,因爲AddItem(5)返回類型 ICollection的,但它是Tint,在這種情況下)。您仍然可以連鎖不過,就在增值的,就像這樣:

List<int> myList = new List<int>(); 
myList.AddItem(5).DoSomethingWithMyInt(); // Not very useful in this case 

這似乎是第一個場景是比較有用的(返回集合),因爲它允許您鏈,馬上最初的賦值語句。這裏有一個更大的示例:

List<int> myList = new List<int>().AddItem(1).AddItem(2).ToList(); 
1

編輯:

List<int> myList = (List<int>) new List<int>().AddItem(1).AddItem(2); 

或者,如果你不想投,你可以說回來ICollection中調用ToList()只是想清楚我希望有一個通用的約束解決方案。

在這種情況下,你的運氣了,因爲返回類型轉換可以是協變,但不是逆變(即你不能隱式轉換從ICollection<T>List<T>),所以沒有一個通用的返回類型不能這樣做。

反正指定2個類型參數有什麼問題?他們可以通過你提供給函數的參數來推斷,所以你甚至不會在你的調用代碼中真正注意到它們。