Объединение в цепочку Дополнительных методов в 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);

Править: Просто требуемый, чтобы быть ясным, что я надеялся на единственное универсальное ограничительное решение.

7
задан Mike_G 9 July 2010 в 20:05
поделиться

5 ответов

Если вам нужно вернуть конкретный тип, вы можете использовать общее ограничение:

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 поддерживает динамический , поэтому вы можете сделать это:

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

Однако я рекомендую универсальную версию с ограничениями, поскольку она более безопасна по типу, более эффективна и позволяет использовать IntelliSense для возвращаемого типа. В более сложных сценариях общие ограничения не всегда могут выразить то, что вам нужно; в этих случаях можно использовать динамический (хотя он не будет связываться с дополнительными методами расширения, поэтому он не работает с цепочкой).

13
ответ дан 6 December 2019 в 09:18
поделиться

Похоже, у вас есть две противоречивые цели, и это сводится к тому, что вы хотите, чтобы ваш метод расширения возвращал:

  • экземпляр, который вызвал метод расширения (коллекцию)
  • ИЛИ элемент, который был добавлен в коллекцию

Из вашего примера использования, процитированного здесь:

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, а T (int, в данном случае). Однако вы все равно можете выстроить цепочку, просто отталкиваясь от добавленного значения, например, так:

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();
2
ответ дан 6 December 2019 в 09:18
поделиться

Хотя у меня нет vs, чтобы попробовать это, что-то в этом роде должно работать:

public static TCollection AddItem<TCollection, TItem>(TCollection collection, 
                                                      TItem itemToAdd) 
where TCollection : ICollection<TItem>
{
    collection.Add(itemToAdd);
    return collection;
}
4
ответ дан 6 December 2019 в 09:18
поделиться

Просто верните ICollection вместо object, и все должно работать так, как вы предполагали.

0
ответ дан 6 December 2019 в 09:18
поделиться

РЕДАКТИРОВАТЬ: Просто хотел прояснить, что я надеялся на единственное общее решение для ограничения.

В этом случае вам не повезло, потому что преобразования типа возвращаемого значения могут быть ковариантными, но не контравариантными (т. Е. Вы не можете неявно преобразовать из ICollection в List ]), поэтому без универсального возвращаемого типа это невозможно.

Что плохого в указании двух параметров типа? Они могут быть выведены из аргументов, которые вы предоставляете функции, поэтому вы даже не заметите их в вызывающем коде.

1
ответ дан 6 December 2019 в 09:18
поделиться