2010-09-15 11 views
27

Dlaczego ta generuje błąd kompilatora:Dlaczego wyrażenie inicjujące kolekcję wymaga implementacji IEnumerable?

class X { public void Add(string str) { Console.WriteLine(str); } } 

static class Program 
{ 
    static void Main() 
    { 
     // error CS1922: Cannot initialize type 'X' with a collection initializer 
     // because it does not implement 'System.Collections.IEnumerable' 
     var x = new X { "string" }; 
    } 
} 

ale to nie:

class X : IEnumerable 
{ 
    public void Add(string str) { Console.WriteLine(str); } 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     // Try to blow up horribly! 
     throw new NotImplementedException(); 
    } 
} 

static class Program 
{ 
    static void Main() 
    { 
     // prints “string” and doesn’t throw 
     var x = new X { "string" }; 
    } 
} 

Co jest powodem ograniczenia inicjatorów Collection - które są cukier syntaktyczny dla wywołania metody Add - do klas implementujących interfejs, który nie ma metody, która nie jest używana?

+4

Jest kilka rzeczy w C# Po prostu nie dostaję. To jedna z nich. Innym jest "foreach". – leppie

+2

@leppie: Czego nie "dostajesz" o foreach? –

+1

@Jon Skeet: Myślę, że leppie odnosi się do faktu, że kompilator po prostu wymaga obecności metody, nie wymagając określonego interfejsu, który jest rodzajem kaczego pisania w mocno napisanym języku. –

Odpowiedz

23

Obiekt obiektinicjator nie; kolekcja inicjator robi. Jest tak, że jest stosowany do klas, które naprawdę reprezentują kolekcje, a nie tylko arbitralne, które mają metodę Add. Muszę przyznać, że tak często "implementowałem" IEnumerable jawnie, tylko po to, aby umożliwić inicjalizację kolekcji - ale wyrzucono NotImplementedException z GetEnumerator().

Należy zauważyć, że na początku rozwoju C# 3 inicjatory kolekcji musiały wdrożyć ICollection<T>, ale okazało się, że jest to zbyt restrykcyjne. Mads Torgersen blogged about this change, i powód żądania IEnumerable, w 2006 roku.

+0

Czy ten sam argument nie dotyczyłby składni zapytania LINQ? Jednak nie wymaga żadnych interfejsów, a nawet pozwala, aby "zmienna iteratora" była nazwą typu, a "Where/Select" by była statyczną metodą ... – Timwi

+0

@Timwi: Sortuj, chociaż jest mniej prawdopodobne, że zapytanie wyrażenie faktycznie skompiluje się przeciwko arbitralnemu typowi niż inicjatorowi kolekcji - podejrzewam, że 'Add' ma więcej" innych znaczeń "niż metody' Where' i 'Select' z odpowiednimi typami parametrów. Zauważ też, że * nie ma * jednego odpowiedniego interfejsu, który mógłby zostać zastosowany do sprawdzania poprawności zapytań LINQ - pomyśl o Reaktywnych Rozszerzeniach, które nie mają żadnego wspólnego interfejsu z LINQ do Obiektów ... –

+6

Nie ma dnia beze mnie .NET 2 była pierwszą wersją ... 90% całego okrucieństwa w .NET wydaje się pochodzić z istnienia .NET 1 z jego nietypowymi rzeczami ... –

Powiązane problemy