Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uwaga / 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ą zawarte 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 .
Kwestia dotycząca mistrza: https://github.com/dotnet/csharplang/issues/9058
Podsumowanie
Zezwól modyfikatorowi partial na zdarzenia i konstruktory na oddzielenie części deklaracji i implementacji, podobnie jak metody częściowe i częściowe właściwości/indeksatory.
partial class C
{
partial C(int x, string y);
partial event Action<int, string> MyEvent;
}
partial class C
{
partial C(int x, string y) { }
partial event Action<int, string> MyEvent
{
add { }
remove { }
}
}
Motywacja
Język C# obsługuje już metody częściowe, właściwości i indeksatory. Brak zdarzeń częściowych i konstruktorów.
Zdarzenia częściowe byłyby przydatne w przypadku słabych bibliotek zdarzeń , w których użytkownik może pisać definicje:
partial class C
{
[WeakEvent]
partial event Action<int, string> MyEvent;
void M()
{
RaiseMyEvent(0, "a");
}
}
Generator źródłowy dostarczany przez bibliotekę zapewnia implementacje:
partial class C
{
private readonly WeakEvent _myEvent;
partial event Action<int, string> MyEvent
{
add { _myEvent.Add(value); }
remove { _myEvent.Remove(value); }
}
protected void RaiseMyEvent(int x, string y)
{
_myEvent.Invoke(x, y);
}
}
Zdarzenia częściowe i konstruktory częściowe byłyby również przydatne do generowania kodu międzyoperacyjnego, takiego jak w środowisku Xamarin , gdzie użytkownik może napisać częściowy konstruktor i definicje zdarzeń:
partial class AVAudioCompressedBuffer : AVAudioBuffer
{
[Export("initWithFormat:packetCapacity:")]
public partial AVAudioCompressedBuffer(AVAudioFormat format, uint packetCapacity);
[Export("create:")]
public partial event EventHandler Created;
}
Generator kodu źródłowego wygeneruje powiązania (do Objective-C w tym przypadku):
partial class AVAudioCompressedBuffer : AVAudioBuffer
{
[BindingImpl(BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]
public partial AVAudioCompressedBuffer(AVAudioFormat format, uint packetCapacity) : base(NSObjectFlag.Empty)
{
// Call Objective-C runtime:
InitializeHandle(
global::ObjCRuntime.NativeHandle_objc_msgSendSuper_NativeHandle_UInt32(
this.SuperHandle,
Selector.GetHandle("initWithFormat:packetCapacity:"),
format.GetNonNullHandle(nameof(format)),
packetCapacity),
"initWithFormat:packetCapacity:");
}
public partial event EventHandler Created
{
add { /* ... */ }
remove { /* ... */ }
}
}
Szczegółowy projekt
Ogólne
Składnia deklaracji zdarzeń (§15.8.1) jest rozszerzona, aby umożliwić partial modyfikatorowi:
event_declaration
- : attributes? event_modifier* 'event' type variable_declarators ';'
+ : attributes? event_modifier* 'partial'? 'event' type variable_declarators ';'
- | attributes? event_modifier* 'event' type member_name
+ | attributes? event_modifier* 'partial'? 'event' type member_name
'{' event_accessor_declarations '}'
;
Składnia deklaracji konstruktora wystąpienia (§15.11.1) jest rozszerzona, aby umożliwić partial modyfikatorowi:
constructor_declaration
- : attributes? constructor_modifier* constructor_declarator constructor_body
+ : attributes? constructor_modifier* 'partial'? constructor_declarator constructor_body
;
Należy pamiętać, że istnieje propozycja zezwolenia modyfikatorowi partial w dowolnym miejscu wśród modyfikatorów, a nie tylko jako ostatnia (również dla metod, właściwości i deklaracji typów).
Deklarację zdarzenia z partial modyfikatorem mówi się, że jest częściową deklaracjązdarzenia i jest skojarzona z co najmniej jednym zdarzeniem częściowym z określonymi nazwami (należy pamiętać, że jedna deklaracja zdarzenia bez metod dostępu może definiować wiele zdarzeń).
Deklarację konstruktora z partial modyfikatorem mówi się, że jest deklaracją konstruktora częściowego i jest skojarzona z konstruktorem częściowym z określonym podpisem.
Mówi się, że częściowa deklaracja zdarzenia jest deklaracją implementującą, gdy określa lub ma modyfikator event_accessor_declarations.
W przeciwnym razie jest to deklaracja definiująca.
Mówi się, że deklaracja konstruktora częściowego jest deklaracją definiującą, kiedy ma ciało złożone z średnika i nie ma modyfikatora extern.
W przeciwnym razie jest to deklaracja implementująca .
partial class C
{
// defining declarations
partial C();
partial C(int x);
partial event Action E, F;
// implementing declarations
partial C() { }
partial C(int x) { }
partial event Action E { add { } remove { } }
partial event Action F { add { } remove { } }
}
Tylko definiująca deklaracja częściowego członka uczestniczy w wyszukiwaniu i jest rozpatrywana w miejscach użycia oraz przy emitowaniu metadanych. (Z wyjątkiem komentarzy dokumentacji, jak opisano poniżej). Sygnatura deklaracji implementowania jest używana do analizy elementów skojarzonych z wartościami null.
Częściowe zdarzenie lub konstruktor:
- Może być zadeklarowana tylko jako członek typu częściowego.
- Musi mieć jedną definicję i jedną deklarację implementaną.
- Nie wolno mieć modyfikatora
abstract. - Nie można jawnie zaimplementować składowej interfejsu.
Zdarzenie częściowe nie jest podobne do pola (§15.8.2), tj.
- Nie ma żadnych magazynów zapasowych ani metod dostępu generowanych przez kompilator.
- Można go używać tylko w operacjach
+=i-=, a nie jako wartości.
Definiowanie deklaracji konstruktora częściowego nie może mieć inicjatora konstruktora (: this() lub : base(); §15.11.2).
Analizowanie przerwania
Zmiana łamiąca zgodność: Zezwolenie modyfikatorowi partial w większej liczbie kontekstów.
class C
{
partial F() => new partial(); // previously a method, now a constructor
@partial F() => new partial(); // workaround to keep it a method
}
class partial { }
Aby uprościć analizator języka, modyfikator partial jest akceptowany w dowolnej deklaracji przypominającej metodę (tj. takie jak lokalne funkcje i metody skryptów najwyższego poziomu), mimo że nie określamy jawnie zmian gramatycznych powyżej.
Atrybuty
Atrybuty wynikowego zdarzenia lub konstruktora są połączonymi atrybutami częściowych deklaracji w odpowiednich pozycjach. Połączone atrybuty są łączone w nieokreślonej kolejności i duplikaty nie są usuwane.
Atrybut methodattribute_target (§22.3) jest ignorowany w przypadku częściowych deklaracji zdarzeń.
Atrybuty akcesorów są używane tylko z deklaracji akcesorów (które mogą być obecne tylko w deklaracji implementującej).
Należy pamiętać, że param i returnattribute_targetsą już ignorowane we wszystkich deklaracjach zdarzeń.
Atrybuty Caller-info w deklaracji implementacyjnej są ignorowane przez kompilator zgodnie z propozycją właściwości częściowych zawartą w sekcji Atrybuty Caller-info (zwróć uwagę, że dotyczy wszystkich częściowych członków, w tym częściowe zdarzenia i konstruktory).
Podpisy
Obie deklaracje częściowego elementu członkowskiego muszą mieć zgodne podpisy, podobnie jak w przypadku właściwości częściowych:
- Różnice typu i rodzaju ref między deklaracjami częściowymi, które są istotne dla środowiska uruchomieniowego, powodują błąd czasu kompilacji.
- Różnice w nazwach elementów krotki między deklaracjami częściowymi powodują błąd w czasie kompilacji.
- Deklaracje muszą mieć te same modyfikatory, chociaż modyfikatory mogą występować w innej kolejności.
- Wyjątek: nie ma to zastosowania do
externmodyfikatora, który może pojawiać się tylko w deklaracji implementowania.
- Wyjątek: nie ma to zastosowania do
- Wszystkie inne różnice składniowe w podpisach deklaracji częściowych powodują ostrzeżenie w czasie kompilacji z następującymi wyjątkami:
- Listy atrybutów nie muszą być zgodne zgodnie z powyższym opisem.
- Różnice w kontekście nullowalności (na przykład nieoznaczone vs. oznaczone) nie powodują ostrzeżeń.
- Domyślne wartości parametrów nie muszą być zgodne, ale jest zgłaszane ostrzeżenie, gdy deklaracja konstruktora implementowania ma domyślne wartości parametrów (ponieważ byłyby one ignorowane, ponieważ tylko deklaracja definiująca uczestniczy w wyszukiwaniu).
- Ostrzeżenie występuje, gdy nazwy parametrów różnią się w zależności od definiowania i implementowania deklaracji konstruktora.
- Różnice dotyczące wartości null, które nie obejmują ignorowania wartości null, powodują ostrzeżenia.
Komentarze do dokumentacji
Można dołączać komentarze dokumentacyjne zarówno w deklaracji definiującej, jak i implementującej. Należy pamiętać, że komentarze dokumentacyjne nie są obsługiwane w przypadku akcesorów zdarzeń.
Gdy komentarze dokumentu są obecne tylko w jednej częściowej deklaracji członkowskiej, te komentarze są stosowane standardowo (są dostępne przez API Roslyn, emitowane do pliku XML dokumentacji).
Gdy komentarze doc są obecne w obu deklaracjach częściowego członka, wszystkie komentarze z deklaracji definiującej są usuwane, a używane są tylko komentarze z deklaracji wykonawczej.
Gdy nazwy parametrów różnią się między deklaracjami częściowego elementu członkowskiego, paramref elementy używają nazw parametrów z deklaracji skojarzonej z komentarzem dokumentacji w kodzie źródłowym.
Na przykład komentarz dokumentacyjny paramref umieszczony w deklaracji implementacji odwołuje się do symboli parametrów tej deklaracji, używając ich nazw parametrów.
Może to być mylące, ponieważ podpis metadanych będzie używać nazw parametrów z deklaracji definiującej.
Zaleca się, aby nazwy parametrów były zgodne z deklaracjami częściowej deklaracji członka, aby uniknąć nieporozumień.
Otwórz pytania
Rodzaje członków
Czy chcemy częściowych zdarzeń, konstruktorów, operatorów, pól? Proponujemy dwa pierwsze rodzaje składowych, ale można rozważyć każdy inny podzestaw.
Można również rozważyć częściowe konstruktory podstawowe , np. zezwalając użytkownikowi na posiadanie tej samej listy parametrów w wielu deklaracjach typu częściowego.
Lokalizacje atrybutów
Czy należy rozpoznać specyfikator docelowy atrybutu [method:] dla zdarzeń częściowych (lub tylko deklaracji definiujących)?
Następnie wynikowe atrybuty metody dostępu byłyby łączeniem atrybutów method-target z obu (lub po prostu definiujących) części deklaracji oraz atrybutów określania wartości docelowej i method-target z metod dostępu deklaracji implementacyjnej.
Połączenie atrybutów z różnych rodzajów deklaracji byłoby bezprecedensowe, a nawet bieżąca implementacja dopasowywania atrybutów w roslyn nie obsługuje tego.
Możemy również rozważyć rozpoznawanie [param:] i [return:], nie tylko w przypadku zdarzeń częściowych, ale także wszystkich zdarzeń podobnych do pól i ekstern.
Aby uzyskać więcej informacji, zobacz https://github.com/dotnet/roslyn/issues/77254.
C# feature specifications