Delegat (CLI) - Delegate (CLI)

Delegat jest formą type-safe funkcji wskaźnik używany przez Common Language Infrastructure (CLI). Delegaci określają metodę do wywołania i opcjonalnie obiekt do wywołania metody. Delegaci są wykorzystywani między innymi do implementowania wywołań zwrotnych i detektorów zdarzeń . Obiekt delegata hermetyzuje odwołanie do metody. Obiekt delegata można następnie przekazać do kodu, który może wywołać metodę, do której się odwołuje , bez konieczności informowania w czasie kompilacji, która metoda zostanie wywołana.

Multicast delegat jest delegatem, który wskazuje na kilka sposobów. Delegowanie multiemisji to mechanizm, który zapewnia funkcjonalność wykonywania więcej niż jednej metody. Istnieje lista delegatów obsługiwana wewnętrznie, a po wywołaniu delegata multiemisji jest wykonywana lista delegatów.

W języku C # delegaci są często używani do implementowania wywołań zwrotnych w programowaniu sterowanym zdarzeniami. Na przykład delegat może służyć do wskazania metody, która powinna zostać wywołana, gdy użytkownik kliknie przycisk. Delegaci umożliwiają programiście powiadomienie kilku metod o wystąpieniu zdarzenia.

Przykład kodu w C #

Kod deklarujący delegate typ o nazwie named SendMessageDelegate , który przyjmuje Message parametr a jako parametr i zwraca void :

delegate void SendMessageDelegate(Message message);

Kod definiujący metodę, która jako argument przyjmuje delegata z instancją:

void SendMessage(SendMessageDelegate sendMessageDelegateReference)
{
    // Call the delegate and any other chained delegates synchronously.
    sendMessageDelegateReference(new Message("hello this is a sample message"));
}

Zaimplementowana metoda, która jest uruchamiana po wywołaniu delegata:

void HandleSendMessage(Message message)
{
    // The implementation for the Sender and Message classes are not relevant to this example.
    Sender.Send(message);
}

Kod do wywołania metody SendMessage, przekazując jako argument delegata, którego wystąpienie zostało utworzone:

SendMessage(new SendMessageDelegate(HandleSendMessage));

Delegaci (C #)

delegate void Notifier(string sender);  // Normal method signature with the keyword delegate

Notifier greetMe;                       // Delegate variable

void HowAreYou(string sender) {
    Console.WriteLine("How are you, " + sender + '?');
}

greetMe = new Notifier(HowAreYou);

Zmienna delegata wywołuje skojarzoną metodę i jest wywoływana w następujący sposób:

greetMe("Anton");                       // Calls HowAreYou("Anton") and prints "How are you, Anton?"

Zmienne delegowane są obiektami pierwszej klasy formularza i można je przypisać do dowolnej metody dopasowywania lub do wartości . Przechowują metodę i jej odbiornik bez żadnych parametrów: new DelegateType(obj.Method)null

new DelegateType(funnyObj.HowAreYou);

Obiekt funnyObj można this i pominąć. Jeśli jest to metoda static , nie powinien to być obiekt (nazywany także instancją w innych językach), ale sama klasa. To nie powinno być abstract , ale może być new , override lub virtual .

Aby wywołać metodę z powodzeniem delegata, podpis metoda musi dopasować DelegateType się z takiej samej liczby parametrów tego samego rodzaju ( ref , out , value ) z tego samego rodzaju (w tym typ zwracany).

Delegaci multiemisji (C #)

Zmienna delegata może jednocześnie zawierać wiele wartości:

void HowAreYou(string sender) {
    Console.WriteLine("How are you, " + sender + '?');
}

void HowAreYouToday(string sender) {
    Console.WriteLine("How are you today, " + sender + '?');
}

Notifier greetMe;

greetMe = HowAreYou;
greetMe += HowAreYouToday;

greetMe("Leonardo");                  // "How are you, Leonardo?"
                                      // "How are you today, Leonardo?"

greetMe -= HowAreYou;

greetMe("Pereira");                   // "How are you today, Pereira?"

Jeśli delegat multiemisji jest funkcją lub nie ma out parametru, zwracany jest parametr ostatniego wywołania.

Szczegóły techniczne wdrożenia

Mimo, że wewnętrzne implementacje mogą różnić się przekazać przypadki mogą być traktowane jako krotka wystąpienia obiektu i sposobu wskaźnika i odniesienia (ewentualnie zerowego) do innego pełnomocnika. Dlatego odwołanie do jednego delegata jest prawdopodobnie odniesieniem do wielu delegatów. Po zakończeniu pierwszego delegata, jeśli jego odwołanie do łańcucha nie ma wartości null, zostanie wywołany następny i tak dalej, aż lista będzie kompletna. Ten wzorzec umożliwia łatwe skalowanie narzutu zdarzenia od pojedynczego odwołania do wysłania do listy delegatów i jest szeroko stosowany w interfejsie wiersza polecenia.

Wydajność

Wydajność delegatów była kiedyś znacznie wolniejsza niż wywołania metody wirtualnej lub interfejsu (6 do 8 razy wolniej w testach porównawczych firmy Microsoft z 2003 r.), Ale od czasu CLR .NET 2.0 w 2005 r. Jest mniej więcej taka sama, jak wywołania interfejsu. Oznacza to, że istnieje niewielki dodatkowy narzut w porównaniu z bezpośrednimi wywołaniami metod.

Istnieją bardzo rygorystyczne zasady dotyczące tworzenia klas delegatów. Reguły te pozwalają optymalizującym kompilatory na dużą swobodę podczas optymalizacji delegatów przy jednoczesnym zapewnieniu bezpieczeństwa typu.

Zobacz też

Bibliografia

Zewnętrzne linki