Действительно ли возможно создать дополнительный метод, который возвращает экземпляр, который вызывает дополнительный метод?
Я хотел бы иметь дополнительный метод для чего-либо, что наследовалось 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);
Править: Просто требуемый, чтобы быть ясным, что я надеялся на единственное универсальное ограничительное решение.
Если вам нужно вернуть конкретный тип, вы можете использовать общее ограничение:
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 для возвращаемого типа. В более сложных сценариях общие ограничения не всегда могут выразить то, что вам нужно; в этих случаях можно использовать динамический
(хотя он не будет связываться с дополнительными методами расширения, поэтому он не работает с цепочкой).
Похоже, у вас есть две противоречивые цели, и это сводится к тому, что вы хотите, чтобы ваш метод расширения возвращал:
Из вашего примера использования, процитированного здесь:
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();
Хотя у меня нет vs, чтобы попробовать это, что-то в этом роде должно работать:
public static TCollection AddItem<TCollection, TItem>(TCollection collection,
TItem itemToAdd)
where TCollection : ICollection<TItem>
{
collection.Add(itemToAdd);
return collection;
}
Просто верните ICollection
вместо object
, и все должно работать так, как вы предполагали.
РЕДАКТИРОВАТЬ: Просто хотел прояснить, что я надеялся на единственное общее решение для ограничения.
В этом случае вам не повезло, потому что преобразования типа возвращаемого значения могут быть ковариантными, но не контравариантными (т. Е. Вы не можете неявно преобразовать из ICollection
в List
]), поэтому без универсального возвращаемого типа это невозможно.
Что плохого в указании двух параметров типа? Они могут быть выведены из аргументов, которые вы предоставляете функции, поэтому вы даже не заметите их в вызывающем коде.