Udostępnij za pośrednictwem


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 z X do interfejsu IEnumerable (ponieważ System.Array implementuje ten interfejs). Typ kolekcji jest interfejsem IEnumerable, typem modułu wyliczającego jest interfejs IEnumerator, a typ elementu jest typem elementu typu tablicy X.

  • Jeśli typ X wyrażenia jest dynamic, istnieje niejawna konwersja z wyrażenia do interfejsu IEnumerable (§10.2.10). Typ kolekcji to interfejs IEnumerable, a typem modułu wyliczającego jest interfejs IEnumerator. Jeśli identyfikator var jest podany jako local_variable_type, typ elementu jest dynamic, w przeciwnym razie jest object.

  • W przeciwnym razie określ, czy typ X ma odpowiednią metodę GetEnumerator:

    • Przeprowadź wyszukiwanie członków dla typu X z identyfikatorem GetEnumerator 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 metody GetEnumerator 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 identyfikatorem Current. 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 identyfikatorem MoveNext 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 jest E, a typ elementu jest typem właściwości Current.
  • 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 interfejsu System.Collections.IEnumerable, to typ kolekcji jest tym interfejsem, typ wyliczający jest interfejsem System.Collections.IEnumerator, a typ elementu jest object.
  • W przeciwnym razie określ, czy typ "X" ma odpowiednią metodę rozszerzenia GetEnumerator:

    • Przeprowadź wyszukiwanie metody rozszerzenia dla typu X z identyfikatorem GetEnumerator. 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 jest in.
    • Jeśli zwracany typ E metody GetEnumerator 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 identyfikatorem Current 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 identyfikatorem MoveNext 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 jest E, a typ elementu jest typem właściwości Current.
  • W przeciwnym razie zostanie wygenerowany błąd i nie zostaną podjęte żadne dalsze kroki.

W przypadku await foreachreguł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.