Kapan Anda akan menggunakan delegasi di C #? [Tutup]

101

Apa penggunaan delegasi Anda di C #?

Maxime Rouiller
sumber
2
Apakah maksud Anda delegasi dalam sistem tipe .NET atau sintaks delegasi C #? Apakah yang Anda maksud adalah "kapan Anda menggunakan sintaks delegasi alih-alih sintaks ekspresi lambda" atau yang Anda maksud adalah "kapan Anda menggunakan delegasi alih-alih class / interfaces / metode virtual / etc."?
Niki

Jawaban:

100

Sekarang kita memiliki ekspresi lambda dan metode anonim di C #, saya menggunakan delegasi lebih banyak lagi. Dalam C # 1, di mana Anda selalu harus memiliki metode terpisah untuk mengimplementasikan logika, menggunakan delegasi seringkali tidak masuk akal. Hari-hari ini saya menggunakan delegasi untuk:

  • Penangan acara (untuk GUI dan lainnya)
  • Benang awal
  • Callback (misalnya untuk async API)
  • LINQ dan sejenisnya (List.Find etc)
  • Di mana pun saya ingin menerapkan kode "template" secara efektif dengan beberapa logika khusus di dalamnya (tempat delegasi memberikan spesialisasi)
Jon Skeet
sumber
Layak untuk menyebut "push" dalam Push LINQ?
Marc Gravell
3
Tidak yakin bagaimana saya akan menjelaskannya secara singkat tanpa membuat hal-hal lebih membingungkan :) (Bisa dibilang itu ditutupi oleh penangan acara, LINQ, dan templaty bitnya!
Jon Skeet
1
Kalimat pertama Anda tidak masuk akal.
senfo
3
Saya tahu apa yang ingin Anda katakan, tetapi saya akan menemukan yang berikut ini lebih mudah dibaca: "Sekarang kita memiliki ekspresi lambda dan metode anonim di C #, saya menggunakan delegasi lebih banyak lagi." Saya tahu saya suka rewel, tapi saya benar-benar harus membaca kalimat itu beberapa kali sebelum masuk akal bagi saya.
senfo
4
1 karena berani menantang Yang Mulia Mr Skeet ;-)
indra
29

Delegasi sangat berguna untuk banyak tujuan.

Salah satu tujuan tersebut adalah menggunakannya untuk memfilter urutan data. Dalam hal ini, Anda akan menggunakan delegasi predikat yang menerima satu argumen dan mengembalikan true atau false tergantung pada implementasi delegasi itu sendiri.

Berikut adalah contoh konyol - saya yakin Anda dapat memperkirakan sesuatu yang lebih berguna dari ini:

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");
    }
}
Andrew Hare
sumber
11
The static Boolean inMyFamily(String name)metode adalah delegasi. Di mana mengambil delegasi sebagai parameter. Karena delegasi hanyalah penunjuk fungsi saat Anda meneruskan nama metode ke .Where(delegate)yang menjadi delegasi. Karena inMyFamily mengembalikan tipe boolean, ini sebenarnya dianggap sebagai predikat. Predikat hanyalah delegasi yang mengembalikan boolean.
Landon Poch
4
"Predikat hanyalah delegasi yang mengembalikan boolean." +1
daehaai
@LandonPoch komentar itu akan ditempatkan lebih baik dalam jawaban. saya sebagai pemula tidak tahu di mana itu. Terima kasih.
Eakan Gopalakrishnan
@Eakan, saya tidak benar-benar menjawab pertanyaan utama (kapan Anda akan menggunakan delegasi) jadi saya meninggalkannya sebagai komentar.
Landon Poch
14

Menemukan jawaban menarik lainnya:

Seorang rekan kerja baru saja menanyakan pertanyaan ini kepada saya - apa gunanya delegasi di .NET? Jawaban saya sangat singkat dan yang tidak dia temukan secara online: untuk menunda pelaksanaan suatu metode.

Sumber: LosTechies

Seperti yang dilakukan LINQ.

Maxime Rouiller
sumber
+1..tidak pernah memikirkannya seperti itu. Poin yang bagus
Luke101
12

Anda dapat menggunakan delegasi untuk mendeklarasikan variabel dan parameter dengan tipe fungsi.

Contoh

Pertimbangkan pola "pinjaman sumber daya". Anda ingin mengontrol pembuatan dan pembersihan sumber daya, sambil mengizinkan kode klien untuk "meminjam" sumber daya di antaranya.

Ini mendeklarasikan tipe delegasi.

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

Metode apa pun yang cocok dengan tanda tangan ini dapat digunakan untuk membuat instance delegasi jenis ini. Di C # 2.0, ini bisa dilakukan secara implisit, cukup dengan menggunakan nama metode, serta dengan menggunakan metode anonim.

Metode ini menggunakan tipe sebagai parameter. Catat permintaan delegasi.

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;
        }
    }
}

Fungsi tersebut dapat dipanggil dengan metode anonim sebagai berikut. Perhatikan bahwa metode anonim dapat menggunakan variabel yang dideklarasikan di luar dirinya sendiri. Ini sangat berguna (meskipun contohnya sedikit dibuat-buat).

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] );
    } );
harpo
sumber
11

Delegasi sering kali dapat digunakan sebagai pengganti antarmuka dengan satu metode, contoh umum dari ini adalah pola pengamat. Dalam bahasa lain jika Anda ingin menerima pemberitahuan bahwa sesuatu telah terjadi, Anda mungkin mendefinisikan sesuatu seperti:

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

Dalam C # ini lebih sering diekspresikan menggunakan peristiwa, di mana penangannya adalah seorang delegasi, misalnya:

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

Tempat lain yang bagus untuk menggunakan delegasi jika ketika Anda harus meneruskan predikat ke dalam suatu fungsi, misalnya saat memilih sekumpulan item dari daftar:

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

Di atas adalah contoh sintaks lambda, yang juga bisa ditulis sebagai berikut:

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

Tempat lain yang berguna untuk menggunakan delegasi adalah mendaftarkan fungsi pabrik, misalnya:

myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);

Saya harap ini membantu!

jonnii
sumber
Contoh bagus dengan sintaks .. Terima kasih .. :)
Raghu
10

Saya datang terlambat tetapi saya mengalami kesulitan untuk mengetahui tujuan delegasi hari ini dan menulis dua program sederhana yang memberikan hasil yang sama yang menurut saya menjelaskan tujuan mereka dengan baik.

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);
    }
}

Delegates.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);
    }
}
akan
sumber
5

Penggunaan yang sedikit berbeda adalah untuk mempercepat refleksi; yaitu daripada menggunakan refleksi setiap kali, Anda dapat menggunakan Delegate.CreateDelegateuntuk membuat delegasi (diketik) ke metode (a MethodInfo), dan memanggil delegasi itu sebagai gantinya. Ini kemudian jauh lebih cepat untuk setiap panggilan, karena pemeriksaan telah dilakukan.

Dengan Expression, Anda juga dapat melakukan hal yang sama untuk membuat kode dengan cepat - misalnya, Anda dapat dengan mudah membuat Expressionyang mewakili operator + untuk jenis yang dipilih saat runtime (untuk memberikan dukungan operator untuk obat generik, yang tidak disediakan oleh bahasa) ; dan Anda dapat mengkompilasi Expressionke delegasi yang diketik - pekerjaan selesai.

Marc Gravell
sumber
5

Delegasi digunakan setiap kali Anda menggunakan acara - itulah mekanisme kerjanya.

Selain itu, delegasi sangat berguna untuk hal-hal seperti menggunakan kueri LINQ. Misalnya, banyak kueri LINQ mengambil delegasi (sering kali Func<T,TResult>) yang dapat digunakan untuk pemfilteran.

Reed Copsey
sumber
4

berlangganan eventhandler ke acara

Manu
sumber
2

Contohnya seperti yang terlihat di sini . Anda memiliki metode untuk memproses objek yang memenuhi persyaratan tertentu. Namun, Anda ingin dapat memproses objek dengan berbagai cara. Alih-alih harus membuat metode terpisah, Anda cukup menetapkan metode pencocokan yang memproses objek ke delegasi dan meneruskan delegasi ke metode yang memilih objek. Dengan begitu, Anda dapat menetapkan metode yang berbeda ke metode satu pemilih. Saya mencoba membuat ini mudah dimengerti.

rookie1024
sumber
1

Saya menggunakan delegasi untuk berkomunikasi dengan utas.

Misalnya, saya mungkin memiliki aplikasi formulir menang yang mengunduh file. Aplikasi memulai utas pekerja untuk melakukan unduhan (yang mencegah GUI mengunci). Utas pekerja menggunakan delegasi untuk mengirim pesan status (misalnya kemajuan unduhan) kembali ke program utama, sehingga GUI dapat memperbarui bilah status.

Danny Frencham
sumber
0
  1. Untuk penanganan acara

  2. Untuk melewatkan metode dalam parameter metode

Patrick Desjardins
sumber
0

Baris penggunaan pertama adalah untuk mengganti pola Observer / Observable (peristiwa). Yang kedua, versi pola Strategi yang bagus dan elegan. Berbagai penggunaan lain dapat dikumpulkan, meskipun lebih esoterik daripada dua yang pertama ini menurut saya.

x0n
sumber
0

Acara, operasi anynch lainnya


sumber
0

Kapan pun Anda ingin merangkum perilaku, tetapi panggil dengan cara yang seragam. Penangan Peristiwa, fungsi panggilan-kembali, dll. Anda dapat mencapai hal-hal serupa menggunakan Antarmuka dan cast, tetapi terkadang, perilaku tidak selalu terkait dengan jenis atau objek . Terkadang Anda hanya memiliki perilaku yang perlu Anda rangkum.

Bob King
sumber
0

Inisialisasi parameter malas! Selain semua jawaban sebelumnya (pola strategi, pola pengamat, dll), delegasi memungkinkan Anda menangani inisialisasi parameter yang lambat. Misalnya, Anda memiliki fungsi Download () yang membutuhkan cukup banyak waktu dan mengembalikan DownloadedObject tertentu. Objek ini dikonsumsi oleh Penyimpanan bergantung pada Kondisi tertentu. Biasanya, Anda akan:

storage.Store(conditions, Download(item))

Namun, dengan delegasi (lebih tepatnya, lambda) Anda bisa melakukan hal berikut, dengan mengubah tanda tangan penyimpanan sehingga menerima Kondisi dan Fungsi <Item, DownloadedObject> dan menggunakannya seperti ini:

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

Oleh karena itu, penyimpanan hanya akan mengevaluasi delegasi jika perlu, menjalankan unduhan bergantung pada Ketentuan.

Santiago Palladino
sumber
Poin kecil, tetapi "lebih tepatnya, lambdas" - Anda dapat melakukan hal yang sama dengan metode anonim di C # 2.0, meskipun akan lebih bertele-tele: delegate (ItemType item) {[return] Download (item);}
Marc Gravell
Tentu, sama seperti LINQ: lambda tidak lebih dari gula sintaksis untuk delegasi. Mereka hanya membuat delegasi lebih mudah diakses.
Santiago Palladino
Lambda sedikit lebih dari sekadar delegasi, karena mereka dapat diubah menjadi pohon ekspresi serta delegasi.
Jon Skeet
Nah, lambda juga bisa dikompilasi menjadi Ekspresi, yang sama sekali berbeda dari delegasi. Tapi contoh Anda menggunakan Func <,>, yang bisa digunakan dari metode anon. Ekspresi akan sangat menyakitkan untuk ditulis dalam C # 2.0.
Marc Gravell
0

Penggunaan delegasi

  1. Penanganan Acara
  2. Multi Casting
Rajeshwaran SP
sumber
0

Parameter perbandingan dalam In Array.Sort (T [] array, Comparisonarison), List.Sort (Perbandingan perbandingan), dll.

GregUzelac
sumber
0

Sejauh yang saya tahu, delegasi dapat diubah menjadi pointer fungsi. Hal ini membuat hidup JAUH lebih mudah saat beroperasi dengan kode native yang menggunakan pointer fungsi, karena mereka dapat berorientasi objek secara efektif, meskipun programmer asli tidak membuat ketentuan apa pun untuk hal itu.

Anak anjing
sumber
0

Delegasi digunakan untuk memanggil metode dengan referensinya. Sebagai contoh:

  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();
        }
    }
mahesh
sumber