7

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

我想为任何继承自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);

编辑:只是想清楚我希望有一个单一的通用约束解决方案。

4

5 回答 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;
}

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

于 2010-07-09T19:58:51.380 回答
4

虽然我没有打开 VS 来尝试这个,但这些方面的东西应该可以工作:

public static TCollection AddItem<TCollection, TItem>(TCollection collection, 
                                                      TItem itemToAdd) 
where TCollection : ICollection<TItem>
{
    collection.Add(itemToAdd);
    return collection;
}
于 2010-07-09T19:59:04.640 回答
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);

或者,如果您不想投射,您可以调用ToList()返回的 ICollection:

List<int> myList = new List<int>().AddItem(1).AddItem(2).ToList();
于 2010-07-09T20:09:17.893 回答
1

编辑:只是想清楚我希望有一个单一的通用约束解决方案。

在这种情况下,您很不走运,因为返回类型转换可以是协变的,但不是逆变的(即您不能隐式转换 from ICollection<T>to List<T>),因此如果没有通用的返回类型,这是无法完成的。

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

于 2010-07-09T20:13:58.317 回答
0

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

于 2010-07-09T20:00:00.660 回答