2010-07-09 104 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个类型参数有什么问题?他们可以通过你提供给函数的参数来推断,所以你甚至不会在你的调用代码中真正注意到它们。