简体   繁体   English

C#中的链接扩展方法

[英]Chaining Extension methods in C#

Is it possible to create an extension method that returns the instance that is invoking the extension method? 是否可以创建一个扩展方法来返回调用该扩展方法的实例?

I would like to have an extension method for anything that inherits from ICollection<T> , returns the object. 我想为从ICollection<T>继承并返回对象的任何对象提供扩展方法。 Much like how jQuery always returns the jquery object. 就像jQuery总是返回jquery对象一样。

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

I imagine something like above, but I am not sure how to get back to the parent to the "this" object type for use of something like this: 我想象上面类似的事情,但是我不确定如何使用“ this”对象类型返回到父对象:

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

EDIT: Just wanted to be clear that i was hoping for a single generic constraint solution. 编辑:只是想清楚一点,我希望有一个通用的约束解决方案。

If you need to return the specific type, you can use a generic constraint: 如果需要返回特定类型,则可以使用通用约束:

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

I tested this and it works in VS2010. 我对此进行了测试,并且可以在VS2010中使用。

Update (regarding jQuery): 更新(关于jQuery):

jQuery chaining works very well because JavaScript uses dynamic typing. jQuery链接非常有效,因为JavaScript使用动态类型。 C# 4.0 supports dynamic , so you can do this: C#4.0支持dynamic ,因此您可以执行以下操作:

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

However, I do recommend the generic constraint version, since it is more type-safe, more efficient, and allows IntelliSense on the returned type. 但是,我还是建议使用通用约束版本,因为它更加类型安全,更有效并且允许对返回的类型使用IntelliSense。 In more complex scenarios, generic constraints aren't always capable of expressing what you need; 在更复杂的场景中,通用约束并不总是能够表达您的需求; in those cases, dynamic can be used (though it won't bind to additional extension methods, so it doesn't work well with chaining). 在这种情况下,可以使用dynamic (尽管它不会绑定到其他扩展方法,所以它不适用于链接)。

While I don't have VS open to try this, something along these lines should work: 虽然我没有开放VS来尝试此操作,但应该遵循以下方法:

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

You seem to have 2 conflicting goals, and it comes down to what do you want your extension method to return: 您似乎有两个相互矛盾的目标,而这取决于您希望扩展方法返回什么:

  • The instance that invoked the extension method (the collection) 调用扩展方法的实例(集合)
  • OR the item that was added to the collection 或添加到集合中的项目

From your example usage, quoted here: 从您的示例用法中,此处引用:

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

You make it look like you want to return the collection. 您使它看起来像您要返回集合。 In any case, that assignment still won't work without a cast, since your extension method would need to have a return type of ICollection, like this: 在任何情况下,如果没有强制转换,该分配仍然无法工作,因为您的扩展方法将需要具有ICollection的返回类型,例如:

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

That would allow you to do this: 那将允许您执行此操作:

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

Now if you'd rather return the object that was added, you still shouldn't have a return type of object . 现在,如果您希望返回添加的对象,则仍然不应该具有object的返回类型。 You should take advantage of your generic type parameter, and return T , like this: 您应该利用通用类型参数,并返回T ,如下所示:

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

However, if you're returning the item that was added, you won't be able to chain like this: 但是,如果您要返回添加的项目,则将无法像这样进行链接:

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

, since the return type of AddItem(5) is not ICollection, but it's T ( int , in this case). ,因为AddItem(5)的返回类型不是 ICollection,而是Tint ,在这种情况下)。 You can still chain though, just off of the value added, like this: 但是,您仍然可以像添加值一样进行链接,如下所示:

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

It seems like the first scenario is more useful (returning the collection), because it does allow you chain, right off of the initial assignment statement. 第一种情况似乎更有用(返回集合),因为它确实允许您从初始赋值语句开始就进行链接。 Here's a larger example of that: 这是一个更大的例子:

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

Or, if you don't want to cast, you can call ToList() on the ICollection that comes back: 或者,如果您不想进行转换,则可以在返回的ICollection上调用ToList()

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

EDIT: Just wanted to be clear that i was hoping for a single generic constraint solution. 编辑:只是想清楚一点,我希望有一个通用的约束解决方案。

In this case you're out of luck because return type conversions can be covariant, but not contravariant (ie you cannot implicitly convert from ICollection<T> to List<T> ), so without a generic return type this cannot be done. 在这种情况下,您很不走运,因为返回类型转换可以是协变的,但不是协变的(即,您不能从ICollection<T>隐式转换为List<T> ),因此,如果没有通用的返回类型,则无法完成。

What's wrong with specifying 2 type parameters anyway? 无论如何指定2个类型参数有什么问题? They can be inferred by the arguments you provide to the function so you won't even really notice them in your calling code. 您可以通过提供给函数的参数来推断它们,因此您甚至不会在调用代码中真正注意到它们。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM