C#中的链接扩展方法

时间:2010-07-09 19:53:01

标签: c# .net extension-methods method-chaining

是否可以创建一个返回调用扩展方法的实例的扩展方法?

我想为从ICollection<T>继承的任何东西都有一个扩展方法,返回该对象。就像jQuery总是返回jquery对象一样。

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

我想象上面的内容,但我不知道如何回到父母的“this”对象类型来使用这样的东西:

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

编辑:只是想明确我希望有一个通用约束解决方案。

5 个答案:

答案 0 :(得分: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;
}

但是,我建议使用通用约束版本,因为它更加类型安全,更高效,并且允许返回类型的IntelliSense。在更复杂的场景中,通用约束并不总能表达您的需求;在这些情况下,可以使用dynamic(虽然它不会绑定到其他扩展方法,因此它不适用于链接)。

答案 1 :(得分:4)

虽然我没有打开VS试试这个,但这些方面应该有用:

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

答案 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 = (List<int>) new List<int>().AddItem(1).AddItem(2);

或者,如果你不想演员,你可以在回来的ICollection上调用ToList()

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

答案 3 :(得分:1)

  

编辑:只是想明确我希望有一个通用约束解决方案。

在这种情况下,你运气不好,因为返回类型转换可以是协变的,但不是逆变的(即你不能隐式地从ICollection<T>转换为List<T>),所以没有通用的返回类型无法完成。

无论如何指定2个类型参数有什么问题?它们可以通过您提供给函数的参数来推断,因此您甚至不会在调用代码中真正注意到它们。

答案 4 :(得分:0)

只需返回ICollection<T>而不是object,一切都应该像您预期的那样工作。