Obsługa GetEnumerator
rozszerzeń dla pętli foreach
.
Notatka
Ten artykuł jest specyfikacją funkcji. Specyfikacja służy jako dokument projektowy dla funkcji. Zawiera proponowane zmiany specyfikacji wraz z informacjami wymaganymi podczas projektowania i opracowywania funkcji. Te artykuły są publikowane do momentu sfinalizowania proponowanych zmian specyfikacji i włączenia ich do obecnej specyfikacji ECMA.
Mogą wystąpić pewne rozbieżności między specyfikacją funkcji a ukończoną implementacją. Te różnice są ujęte w odpowiednich notatkach ze spotkania dotyczącego projektowania języka (LDM).
Więcej informacji na temat procesu wdrażania specyfikacji funkcji można znaleźć w standardzie języka C# w artykule dotyczącym specyfikacji .
Streszczenie
Pozwól pętlom foreach
rozpoznać metodę rozszerzającą GetEnumerator
, która spełnia wzorzec foreach, i przetwarzać wyrażenie, gdy w innym przypadku wystąpiłby błąd.
Motywacja
Spowoduje to, że foreach
będzie zgodny z tym, jak inne funkcje są implementowane w języku C#, w tym funkcje asynchroniczne i dekonstrukcję opartą na wzorcach.
Szczegółowy projekt
Zmiana specyfikacji jest stosunkowo prosta. Modyfikujemy sekcję The foreach statement
§13.9.5 na następujący tekst:
Przetwarzanie instrukcji foreach w czasie kompilacji najpierw określa typ kolekcji , typ modułu wyliczającego oraz typ elementu wyrażenia. Ta determinacja jest przeprowadzana w następujący sposób:
Jeśli typ
X
wyrażenia jest typem tablicy, istnieje niejawna konwersja odwołania zX
do interfejsuIEnumerable
(ponieważSystem.Array
implementuje ten interfejs). Typ kolekcji jest interfejsemIEnumerable
, typem modułu wyliczającego jest interfejsIEnumerator
, a typ elementu jest typem elementu typu tablicyX
.Jeśli typ
X
wyrażenia jestdynamic
, istnieje niejawna konwersja z wyrażenia do interfejsuIEnumerable
(§10.2.10). Typ kolekcji to interfejsIEnumerable
, a typem modułu wyliczającego jest interfejsIEnumerator
. Jeśli identyfikatorvar
jest podany jako local_variable_type, typ elementu jestdynamic
, w przeciwnym razie jestobject
.W przeciwnym razie określ, czy typ
X
ma odpowiednią metodęGetEnumerator
:
- Przeprowadź wyszukiwanie członków dla typu
X
z identyfikatoremGetEnumerator
i bez argumentów typu. Jeśli wyszukiwanie członka nie daje dopasowania, powoduje niejednoznaczność lub zwraca dopasowanie, które nie jest zbiorem metod, sprawdź, czy istnieje interfejs wyliczalny zgodnie z poniższym opisem. Zaleca się, aby ostrzeżenie zostało wydane, jeśli wyszukiwanie elementu członkowskiego generuje cokolwiek oprócz grupy metod lub braku dopasowania.- Przeprowadź rozpoznawanie przeciążeń przy użyciu wynikowej grupy metod i pustej listy argumentów. Jeśli rozpoznawanie przeciążenia nie powoduje zastosowania metod, powoduje niejednoznaczność lub powoduje utworzenie jednej najlepszej metody, ale ta metoda jest statyczna lub nie jest publiczna, sprawdź interfejs wyliczalny, jak opisano poniżej. Zaleca się, aby ostrzeżenie zostało wydane, jeśli rozwiązanie przeciążenia produkuje coś innego niż jednoznaczną metodę instancji publicznej lub brak odpowiednich metod.
- Jeśli zwracany typ
E
metodyGetEnumerator
nie jest klasą, strukturą ani typem interfejsu, zostanie wygenerowany błąd i nie zostaną wykonane żadne dalsze kroki.- Wyszukiwanie członków jest wykonywane na
E
bez argumentów typu z identyfikatoremCurrent
. Jeśli wyszukiwanie elementu członkowskiego nie daje dopasowania, wynik jest błędem lub wynikiem jest wszystko, z wyjątkiem właściwości wystąpienia publicznego, która zezwala na odczyt, zostanie wygenerowany błąd i nie zostaną podjęte żadne dalsze kroki.- Wyszukiwanie elementu jest wykonywane na
E
z identyfikatoremMoveNext
i bez argumentów typu. Jeśli wyszukiwanie członka nie daje dopasowania lub wynikiem jest coś poza grupą metod, generowany jest błąd i nie są wykonywane żadne dalsze kroki.- Rozpoznawanie przeciążenia jest wykonywane w grupie metod z pustą listą argumentów. Jeśli rozpoznawanie przeciążenia nie powoduje żadnych odpowiednich metod, powoduje niejednoznaczność lub powoduje utworzenie jednej najlepszej metody, ale ta metoda jest statyczna lub nie jest publiczna lub jej typ zwracany nie jest
bool
, zostanie wygenerowany błąd i nie zostaną podjęte żadne dalsze kroki.- Typ kolekcji jest
X
, typ modułu wyliczającego jestE
, a typ elementu jest typem właściwościCurrent
.W przeciwnym razie, sprawdź, czy dostępny jest interfejs wyliczalny.
- Jeśli wśród wszystkich typów
, dla których istnieje niejawna konwersja z na , istnieje unikatowy typ taki, że nie jest i dla wszystkich innych istnieje niejawna konwersja z na , wówczas typ kolekcji jest interfejsem , typ modułu wyliczającego to interfejs , a typ elementu jest . - W przeciwnym razie, jeśli istnieje więcej niż jeden taki typ
T
, zostanie wygenerowany błąd i nie zostaną podjęte żadne dalsze kroki.- W przeciwnym razie, jeśli istnieje niejawna konwersja z
X
do interfejsuSystem.Collections.IEnumerable
, to typ kolekcji jest tym interfejsem, typ wyliczający jest interfejsemSystem.Collections.IEnumerator
, a typ elementu jestobject
.W przeciwnym razie określ, czy typ "X" ma odpowiednią metodę rozszerzenia
GetEnumerator
:
- Przeprowadź wyszukiwanie metody rozszerzenia dla typu
X
z identyfikatoremGetEnumerator
. Jeśli wyszukiwanie członka nie daje dopasowania, generuje niejednoznaczność lub generuje dopasowanie, które nie jest grupą metod, występuje błąd i nie są podejmowane żadne dalsze kroki. Zaleca się, aby należy wydać ostrzeżenie, jeśli wyszukiwanie elementów członkowskich generuje coś innego, niż grupa metod lub brak dopasowania.- Przeprowadź rozpoznawanie przeciążeń przy użyciu wynikowej grupy metod i pojedynczego argumentu typu
X
. Jeśli rozpoznawanie przeciążenia nie generuje żadnych odpowiednich metod, powoduje niejednoznaczność lub powoduje utworzenie jednej najlepszej metody, ale ta metoda nie jest dostępna, zostanie wygenerowany błąd, nie zostaną wykonane żadne dalsze kroki.
- To rozwiązanie zezwala na przekazanie pierwszego argumentu przez referencję, jeśli
X
jest typem struktury, a rodzaj referencji jestin
.- Jeśli zwracany typ
E
metodyGetEnumerator
nie jest klasą, strukturą ani typem interfejsu, zostanie wygenerowany błąd i nie zostaną wykonane żadne dalsze kroki.- Wyszukiwanie członka jest wykonywane na
E
z identyfikatoremCurrent
i bez argumentów typu. Jeśli wyszukiwanie elementu członkowskiego nie daje dopasowania, wynik jest błędem lub wynikiem jest wszystko, z wyjątkiem właściwości wystąpienia publicznego, która zezwala na odczyt, zostanie wygenerowany błąd i nie zostaną podjęte żadne dalsze kroki.- Wyszukiwanie członków jest wykonywane na
E
z identyfikatoremMoveNext
i bez argumentów typu. Jeśli wyszukiwanie członka nie daje dopasowania, wynik jest błędem lub wynikiem jest coś innego niż grupa metod, generowany jest błąd i nie są podejmowane dalsze kroki.- Rozpoznawanie przeciążenia jest wykonywane w grupie metod z pustą listą argumentów. Jeśli rozpoznawanie przeciążenia nie powoduje żadnych odpowiednich metod, powoduje niejednoznaczność lub powoduje utworzenie jednej najlepszej metody, ale ta metoda jest statyczna lub nie jest publiczna lub jej typ zwracany nie jest
bool
, zostanie wygenerowany błąd i nie zostaną podjęte żadne dalsze kroki.- Typ kolekcji jest
X
, typ modułu wyliczającego jestE
, a typ elementu jest typem właściwościCurrent
.W przeciwnym razie zostanie wygenerowany błąd i nie zostaną podjęte żadne dalsze kroki.
W przypadku await foreach
reguły są podobnie modyfikowane. Jedyną zmianą wymaganą do tej specyfikacji jest usunięcie wiersza Extension methods do not contribute.
z opisu, ponieważ reszta tej specyfikacji jest oparta na powyższych regułach o różnych nazwach zastąpionych metodami wzorca.
Wady i niedogodności
Każda zmiana zwiększa złożoność języka i potencjalnie pozwala, aby elementy, które nie zostały zaprojektowane do foreach
, były foreach
, takie jak Range
.
Alternatywy
Nic nie robi.
Nierozwiązane pytania
Nic w tym momencie.
C# feature specifications