2010-07-09 14 views
7

Czy jest możliwe utworzenie metody rozszerzenia, która zwraca instancję, która wywołuje metodę rozszerzenia?Metody łączenia łańcuchów w C#

Chciałbym mieć metodę rozszerzenia dla wszystkiego, co dziedziczy po ICollection<T>, zwraca obiekt. Podobnie jak jQuery zawsze zwraca obiekt jquery.

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

sobie wyobrazić coś takiego jak powyżej, ale nie jestem pewien, jak wrócić do rodziców do „tego” typu obiektu do użytku mniej więcej tak:

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

EDIT: Po prostu chciał jasne, że liczyłem na jedno ogólne rozwiązanie przymusu.

Odpowiedz

13

Jeśli trzeba zwrócić konkretnego typu, można użyć rodzajowe ograniczenie:

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

testowałem to i działa w VS2010.

Update (dotyczące jQuery):

jQuery łańcuchowym działa bardzo dobrze, ponieważ JavaScript wykorzystuje dynamiczne pisanie. C# 4.0 obsługuje dynamic, więc można to zrobić:

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

Ja jednak polecam generycznej wersji ograniczeń, ponieważ jest bardziej bezpieczny typu, bardziej wydajny i pozwala na IntelliSense zwracanego typu. W bardziej złożonych scenariuszach ogólne ograniczenia nie zawsze są w stanie wyrazić to, czego potrzebujesz; w takich przypadkach można użyć dynamic (choć nie będzie to wiązało się z dodatkowymi metodami rozszerzenia, więc nie działa dobrze z łańcuchem).

+0

Dzięki. Zrobiłem to na początku, ale nie podoba mi się 2 specyfikacja generyczna. ALE, doszedłem do wniosku, że skoro typ jest domniemany w TCollection, nie musisz go podawać w kodzie. –

+0

Dobrze. Kod, aby go użyć jest dokładnie tym, co masz w swoim pytaniu; nie są wymagane żadne jawne parametry. Zaktualizowałem również odpowiedź dotyczącą jQuery. –

4

Chociaż nie mam VS otwarty spróbować tego, coś w tym kierunku powinno działać:

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

Wystarczy powrócić ICollection<T> zamiast object i wszystko powinno działać jak zamierzałeś go.

+1

Nie, ponieważ przypisuje go zmiennej typu "List ". –

+1

To prawda. Pomyłkowo myślałem, że obsada nie działała, ale to był ReSharper stawiając czerwoną falistą linię i po prostu trwało dużo czasu, aby zaktualizować po zastąpieniu poprzedniej składni. –

+1

Przepraszam, znowu się mylę, Adam ma rację. –

2

Wydajesz się mieć 2 sprzeczne cele, a wszystko sprowadza się do tego, co chcesz swoją metodę rozszerzenia do powrotu:

  • Instancja, która powołuje się na metodę rozszerzenia (kolekcja)
  • lub towar który został dodany do kolekcji

ze swojego przykład użycia, cytowany tutaj:

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

Wygląda na to, że chcesz zwrócić kolekcję.W każdym razie, że przypisanie nadal nie będzie działać bez obsady, gdyż metoda rozszerzenie musiałaby mieć typ zwracanej kolekcji ICollection, tak:

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

To pozwoli Ci to zrobić:

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

Teraz, jeśli wolisz zwrócić obiekt, który został dodany, nadal nie powinieneś mieć typu zwrotu: object. Należy skorzystać z twojej rodzajowego parametr typu i powrócić T, tak:

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

Jednakże, jeśli jesteś wracać rzecz, która została dodana, nie będzie w stanie łańcuchu:

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

, gdyż typ powrót AddItem(5) jest nie ICollection, ale to T (int, w tym przypadku). Można nadal przykuwają jednak właśnie od wartości dodanej, takich jak to:

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

Wydaje się pierwszy scenariusz jest bardziej przydatna (powrót kolekcji), ponieważ nie pozwala łańcuch, tuż początkowa instrukcja przypisania. Oto większy przykładem:

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

Lub, jeśli nie chcesz rzucić, można nazwać ToList() w kolekcji ICollection że wraca:

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

EDIT: Po prostu chciał jasne, że miałem nadzieję na jedno ogólne rozwiązanie przymusu.

W tym przypadku pecha bo Zwraca typ konwersji może być kowariantna, ale nie kontrawariantny (to znaczy nie można niejawnie przekonwertować z ICollection<T> do List<T>), więc bez generycznego typ zwracany nie można tego zrobić.

Co jest nie tak z określeniem 2 parametrów typu? Można je wywnioskować na podstawie argumentów podanych w funkcji, dzięki czemu nie zauważysz ich w swoim kodzie wywołującym.

Powiązane problemy