Kiedy używać delegatów w C#? [zamknięte]

Jakie są Twoje zastosowania delegatów w C#?

Author: Bill the Lizard, 2008-10-10

20 answers

Teraz, gdy mamy wyrażenia lambda i metody anonimowe w C#, używam delegatów znacznie więcej. W C# 1, gdzie zawsze trzeba było mieć osobną metodę implementacji logiki, używanie delegata często nie miało sensu. W dzisiejszych czasach używam delegatów do:

  • obsługa zdarzeń (dla GUI i nie tylko)
  • Rozpoczynanie wątków
  • wywołania zwrotne (np. dla interfejsów API async)
  • LINQ i podobne (List.Find etc)
  • gdzie indziej, gdzie chcę skutecznie zastosować kod "szablon" z niektóre wyspecjalizowane logiki wewnątrz (gdzie delegat zapewnia specjalizację)
 97
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-19 16:19:03

Delegaci są bardzo przydatni do wielu celów.

Jednym z takich celów jest wykorzystanie ich do filtrowania sekwencji danych. W tym przypadku można użyć delegata predykatu, który akceptuje jeden argument i zwraca true lub false w zależności od implementacji samego delegata.

Oto głupi przykład - jestem pewien, że można ekstrapolować coś bardziej użytecznego z tego:

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<String> names = new List<String>
        {
            "Nicole Hare",
            "Michael Hare",
            "Joe Hare",
            "Sammy Hare",
            "George Washington",
        };

        // Here I am passing "inMyFamily" to the "Where" extension method
        // on my List<String>.  The C# compiler automatically creates 
        // a delegate instance for me.
        IEnumerable<String> myFamily = names.Where(inMyFamily);

        foreach (String name in myFamily)
            Console.WriteLine(name);
    }

    static Boolean inMyFamily(String name)
    {
        return name.EndsWith("Hare");
    }
}
 27
Author: Andrew Hare,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-31 19:11:41

Znaleziono inną ciekawą odpowiedź:

Pewien współpracownik zadał mi właśnie takie pytanie - po co delegaci w. NET? moja odpowiedź była bardzo krótka i taka, której nie znalazł w Internecie: opóźnić wykonanie metody.

Source: LosTechies

Tak jak robi LINQ.

 13
Author: Maxime Rouiller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-16 18:12:31

Możesz używać delegatów do deklarowania zmiennych i parametrów typowanych przez funkcje.

Przykład

Rozważ wzorzec "pożyczanie zasobów". Chcesz kontrolować tworzenie i czyszczenie zasobu, jednocześnie pozwalając kodowi klienta na "wypożyczenie" zasobu pomiędzy.

To deklaruje typ delegata.

public delegate void DataReaderUser( System.Data.IDataReader dataReader );

Każda metoda pasująca do tego podpisu może być użyta do utworzenia instancji delegata tego typu. W C # 2.0 można to zrobić bezwarunkowo, po prostu używając nazwę metody, a także za pomocą metod anonimowych.

Ta metoda wykorzystuje Typ jako parametr. Zwróć uwagę na zaproszenie delegata.

public class DataProvider
{
    protected string _connectionString;

    public DataProvider( string psConnectionString )
    {
        _connectionString = psConnectionString;
    }

    public void UseReader( string psSELECT, DataReaderUser readerUser )
    {
        using ( SqlConnection connection = new SqlConnection( _connectionString ) )
        try
        {
            SqlCommand command = new SqlCommand( psSELECT, connection );
            connection.Open();
            SqlDataReader reader = command.ExecuteReader();

            while ( reader.Read() )
                readerUser( reader );  // the delegate is invoked
        }
        catch ( System.Exception ex )
        {
            // handle exception
            throw ex;
        }
    }
}

Funkcję można wywołać za pomocą metody anonimowej w następujący sposób. Zauważ, że metoda anonimowa może używać zmiennych zadeklarowanych poza . Jest to niezwykle przydatne (choć przykład jest trochę wymyślony).

string sTableName = "test";
string sQuery = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + sTableName + "'";

DataProvider.UseReader( sQuery,
    delegate( System.Data.IDataReader reader )
    {
        Console.WriteLine( sTableName + "." + reader[0] );
    } );
 12
Author: harpo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 13:27:07

Delegaty mogą być często używane zamiast interfejsu z jedną metodą, powszechnym przykładem tego może być wzorzec obserwatora. W innych językach Jeśli Chcesz otrzymać powiadomienie, że coś się stało, możesz zdefiniować coś w stylu:

class IObserver{ void Notify(...); }

W C# jest to częściej wyrażane za pomocą zdarzeń, gdzie obsługa Jest delegatem, na przykład:

myObject.SomeEvent += delegate{ Console.WriteLine("..."); };

Kolejne świetne miejsce do wykorzystania delegatów, jeśli musisz przekazać predykat do funkcji, na przykład gdy wybór zestawu elementów z listy:

myList.Where(i => i > 10);

Powyższy przykład jest przykładem składni lambda, która również mogła być napisana w następujący sposób:

myList.Where(delegate(int i){ return i > 10; });

Innym miejscem, w którym może być przydatne użycie delegatów, jest rejestracja funkcji fabrycznych, na przykład:

myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);
Mam nadzieję, że to pomoże!
 10
Author: jonnii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-31 19:04:55

Wchodzę w to bardzo późno, ale miałem problem z pojęciem celu delegatów dzisiaj i napisałem dwa proste programy, które dają ten sam wynik, który myślę, że dobrze wyjaśnia ich cel.

NoDelegates.cs

using System;

public class Test {
    public const int MAX_VALUE = 255;
    public const int MIN_VALUE = 10;

    public static void checkInt(int a) {
        Console.Write("checkInt result of {0}: ", a);
        if (a < MAX_VALUE && a > MIN_VALUE)
            Console.WriteLine("max and min value is valid");
        else
            Console.WriteLine("max and min value is not valid");
    }

    public static void checkMax(int a) {
        Console.Write("checkMax result of {0}: ", a);
        if (a < MAX_VALUE)
            Console.WriteLine("max value is valid");
        else
            Console.WriteLine("max value is not valid");
    }

    public static void checkMin(int a) {
        Console.Write("checkMin result of {0}: ", a);
        if (a > MIN_VALUE)
            Console.WriteLine("min value is valid");
        else
            Console.WriteLine("min value is not valid");
        Console.WriteLine("");
    }
}

public class Driver {
    public static void Main(string [] args) {
        Test.checkInt(1);
        Test.checkMax(1);
        Test.checkMin(1);

        Test.checkInt(10);
        Test.checkMax(10);
        Test.checkMin(10);

        Test.checkInt(20);
        Test.checkMax(20);
        Test.checkMin(20);

        Test.checkInt(30);
        Test.checkMax(30);
        Test.checkMin(30);

        Test.checkInt(254);
        Test.checkMax(254);
        Test.checkMin(254);

        Test.checkInt(255);
        Test.checkMax(255);
        Test.checkMin(255);

        Test.checkInt(256);
        Test.checkMax(256);
        Test.checkMin(256);
    }
}

Delegaci.cs

using System;

public delegate void Valid(int a);

public class Test {
    public const int MAX_VALUE = 255;
    public const int MIN_VALUE = 10;

    public static void checkInt(int a) {
        Console.Write("checkInt result of {0}: ", a);
        if (a < MAX_VALUE && a > MIN_VALUE)
            Console.WriteLine("max and min value is valid");
        else
            Console.WriteLine("max and min value is not valid");
    }

    public static void checkMax(int a) {
        Console.Write("checkMax result of {0}: ", a);
        if (a < MAX_VALUE)
            Console.WriteLine("max value is valid");
        else
            Console.WriteLine("max value is not valid");
    }

    public static void checkMin(int a) {
        Console.Write("checkMin result of {0}: ", a);
        if (a > MIN_VALUE)
            Console.WriteLine("min value is valid");
        else
            Console.WriteLine("min value is not valid");
        Console.WriteLine("");
    }
}

public class Driver {
    public static void Main(string [] args) {
        Valid v1 = new Valid(Test.checkInt);
        v1 += new Valid(Test.checkMax);
        v1 += new Valid(Test.checkMin);
        v1(1);
        v1(10);
        v1(20);
        v1(30);
        v1(254);
        v1(255);
        v1(256);
    }
}
 10
Author: will,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 22:01:00

Zamiast używać reflection za każdym razem, możesz użyć Delegate.CreateDelegate do utworzenia (wpisanego) delegata do metody (a MethodInfo) i wywołać tego delegata. To jest wtedy dużo szybciej na połączenie, ponieważ kontrole zostały już wykonane.

Za pomocą Expression Możesz również zrobić to samo, aby utworzyć kod w locie - na przykład możesz łatwo utworzyć Expression, który reprezentuje operator + dla typu wybranego w czasie wykonywania (aby zapewnić obsługę operatora dla generyków, których język nie dostarcza); i możesz skompilować Expression do typowanego delegata-zadanie wykonane.

 5
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 13:24:55

Delegaty są używane za każdym razem, gdy używasz zdarzeń - to jest mechanizm, za pomocą którego działają.

Dodatkowo, delegaty są bardzo przydatne do takich rzeczy jak używanie zapytań LINQ. Na przykład, wiele zapytań LINQ przyjmuje delegata (często Func<T,TResult>), który może być użyty do filtrowania.

 5
Author: Reed Copsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-31 19:01:07

Subskrybowanie eventhandlers do eventów

 4
Author: Manu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 13:05:11

Przykład może być widoczny tutaj. Masz metodę przetwarzania obiektu, który spełnia określone wymagania. Chcesz jednak móc przetwarzać obiekt na wiele sposobów. Zamiast tworzyć oddzielne metody, można po prostu przypisać metodę dopasowania, która przetwarza obiekt do delegata i przekazać delegata do metody, która wybiera obiekty. W ten sposób można przypisać różne metody do metody one selector. Próbowałem to łatwo zrobić. to zrozumiałe.

 2
Author: rookie1024,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-11 04:14:24

Używam delegatów do komunikacji z wątkami.

Na przykład mogę mieć aplikację win forms, która pobiera plik. Aplikacja uruchamia wątek roboczy do pobrania (co zapobiega blokowaniu interfejsu graficznego). Wątek roboczy używa delegatów do wysyłania wiadomości o statusie (np. postęp pobierania) z powrotem do głównego programu, dzięki czemu GUI może zaktualizować pasek stanu.

 1
Author: Danny Frencham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-21 03:41:02
  1. Dla obsługi zdarzeń

  2. Aby przekazać metodę w parametrach metody

 0
Author: Patrick Desjardins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 13:07:52

Pierwsza linia użycia polega na zastąpieniu wzorca Observer/Observable (events). Druga, Ładna elegancka wersja wzorca strategii. Można zebrać różne inne zastosowania, choć bardziej Ezoteryczne niż te dwa pierwsze, jak sądzę.

 0
Author: x0n,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 13:08:03

Zdarzenia, inne operacje anynch

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 13:08:13

Za każdym razem, gdy chcesz zamknąć zachowanie, ale wywołaj je w jednolity sposób. Obsługa zdarzeń, funkcje oddzwaniania itp. Można osiągnąć podobne rzeczy za pomocą interfejsów i odlewów, ale czasami zachowanie nie musi być powiązane z typem lub obiektem. Czasami po prostu masz zachowanie, które musisz zamknąć.

 0
Author: Bob King,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 13:09:56

Inicjalizacja leniwego parametru! Oprócz wszystkich poprzednich odpowiedzi (wzorzec strategii, wzorzec obserwatora, itp.), delegaty pozwalają na obsługę leniwej inicjalizacji parametrów. Załóżmy na przykład, że masz funkcję Download (), która zajmuje sporo czasu i zwraca określony obiekt DownloadedObject. Obiekt ten jest zużywany przez magazyn w zależności od pewnych warunków. Zazwyczaj:

storage.Store(conditions, Download(item))

Jednak przy pomocy delegatów (dokładniej lambda) można wykonać następujące czynności, zmieniając podpis sklepu tak, że otrzymuje warunek i Func i używać go w ten sposób:

storage.Store(conditions, (item) => Download(item))

Dlatego storage oceni delegata tylko w razie potrzeby, wykonując pobieranie w zależności od warunków.

 0
Author: Santiago Palladino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 13:18:12

Użycie delegatów

  1. Obsługa Zdarzeń
  2. Multi Casting
 0
Author: Rajeshwaran S P,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-10 13:37:41

The comparison param in in Array.Sort (t [] array, Comparison comparison), List.Sort (Comparison comparison), etc

 0
Author: GregUzelac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-11 15:12:19

Z tego co wiem, delegaty mogą być konwertowane na Wskaźniki funkcji. To znacznie ułatwia życie podczas współdziałania z natywnym kodem, który pobiera Wskaźniki funkcji, ponieważ mogą one być zorientowane obiektowo, nawet jeśli oryginalny programista nie przewidział tego.

 0
Author: Puppy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-25 16:25:02

Delegaty są używane do wywołania metody przez jej odniesienie. Na przykład:

  delegate void del_(int no1,int no2);
class Math
{
   public static void add(int x,int y)
   {
     Console.WriteLine(x+y);
   }
   public static void sub(int x,int y)
   {
     Console.WriteLine(x-y);
   }
}



    class Program
    {
        static void Main(string[] args)
        {
            del_ d1 = new del_(Math.add);
            d1(10, 20);
            del_ d2 = new del_(Math.sub);
            d2(20, 10);
            Console.ReadKey();
        }
    }
 0
Author: mahesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-26 11:38:30