Temsilcileri C # 'da ne zaman kullanırsınız? [kapalı]


101

C # 'da temsilci kullanımınız nedir?


2
.NET türü sistemdeki temsilcilerden mi yoksa C # temsilci sözdiziminden mi bahsediyorsunuz? "Lambda ifade sözdizimi yerine temsilci sözdizimini ne zaman kullanıyorsunuz" mu yoksa "sınıflar / arabirimler / sanal yöntemler / vb. Yerine temsilciler ne zaman kullanıyorsunuz" mu demek istiyorsunuz?
Niki

Yanıtlar:


100

Artık C # 'da lambda ifadeleri ve anonim yöntemlere sahip olduğumuza göre, delegeleri çok daha fazla kullanıyorum. Mantığı uygulamak için her zaman ayrı bir yönteme sahip olmanız gereken C # 1'de, bir temsilci kullanmak çoğu zaman bir anlam ifade etmiyordu. Bugünlerde delegeleri şunlar için kullanıyorum:

  • Olay işleyicileri (GUI ve daha fazlası için)
  • Başlangıç ​​konuları
  • Geri aramalar (ör. Eşzamansız API'ler için)
  • LINQ ve benzeri (List.Find vb.)
  • İçinde bazı özel mantık bulunan "şablon" kodunu etkili bir şekilde uygulamak istediğim başka herhangi bir yerde (temsilcinin uzmanlık sağladığı yerlerde)

Push LINQ'daki "push" dan bahsetmeye değer mi?
Marc Gravell

3
İşleri daha kafa karıştırıcı hale getirmeden kısaca nasıl açıklayacağımdan emin değilim :) (Muhtemelen olay işleyicileri, LINQ ve şablonla ilgili kısımlar tarafından kapsanmaktadır!
Jon Skeet

1
İlk cümlenin pek mantıklı değil.
senfo

3
Ne söylemeye çalıştığınızı biliyorum, ancak şunu okumayı daha kolay bulabilirim: "Artık C # lambda ifadeleri ve anonim yöntemlere sahip olduğumuza göre, delegeleri daha çok kullanıyorum." Biliyorum, kusura bakma ama bu cümleyi bana mantıklı gelmeden önce birkaç kez okumam gerekiyordu.
senfo

4
Saygıdeğer Bay Skeet ;-) ile meydan okuma cesareti için +1
indra

29

Delegeler birçok amaç için çok kullanışlıdır.

Böyle bir amaç, bunları veri dizilerini filtrelemek için kullanmaktır. Bu durumda, bir bağımsız değişkeni kabul eden ve temsilcinin uygulamasına bağlı olarak doğru veya yanlış döndüren bir yüklem delege kullanırsınız.

İşte aptalca bir örnek - Bundan daha yararlı bir şey çıkarabileceğinize eminim:

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

11
static Boolean inMyFamily(String name)Yöntem temsilci olduğu. Bir temsilciyi parametre olarak nerede alır. Temsilciler, yöntem adını .Where(delegate)temsilci haline getirdiğinizde yalnızca işlev işaretçileri olduğundan . İnMyFamily bir boole türü döndürdüğünden, aslında bir yüklem olarak kabul edilir. Dayanaklar yalnızca booleleri döndüren temsilcilerdir.
Landon Poch

4
"Dayanaklar sadece booleleri döndüren delegelerdir." +1
daehaai

@LandonPoch, bu yorumun cevaba daha iyi yerleştirilmesi gerekirdi. yeni başlayan biri olarak nerede olduğunu anlayamadım. Teşekkürler.
Eakan Gopalakrishnan

@Eakan, ana soruyu gerçekten cevaplamıyordum (delegeleri ne zaman kullanırdın) bu yüzden yorum olarak bıraktım.
Landon Poch

14

Başka ilginç bir cevap buldum:

Bir iş arkadaşım az önce bana şu soruyu sordu - .NET'teki temsilcilerin amacı nedir? Cevabım çok kısaydı ve internette bulamadığı bir şeydi: bir yöntemin uygulanmasını geciktirmek.

Kaynak: LosTechies

Tıpkı LINQ'nun yaptığı gibi.


+1. Böyle düşünmemişti. İyi nokta
Luke101

12

Fonksiyon tipli değişkenleri ve parametreleri bildirmek için temsilciler kullanabilirsiniz.

Misal

"Kaynak ödünç alma" modelini düşünün. Müşteri kodunun aradaki kaynağı "ödünç almasına" izin verirken, bir kaynağın oluşturulmasını ve temizlenmesini kontrol etmek istersiniz.

Bu, bir temsilci türü bildirir.

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

Bu imzayla eşleşen herhangi bir yöntem, bu türden bir temsilciyi başlatmak için kullanılabilir. C # 2.0'da, bu örtük olarak, yalnızca yöntemin adını kullanarak veya anonim yöntemler kullanarak yapılabilir.

Bu yöntem, türü bir parametre olarak kullanır. Temsilcinin çağrısını not edin.

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

İşlev, aşağıdaki gibi anonim bir yöntemle çağrılabilir. Anonim yöntemin kendi dışında bildirilen değişkenleri kullanabileceğini unutmayın . Bu son derece kullanışlıdır (örnek biraz yapmacık olsa da).

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

11

Temsilciler genellikle bir yöntemle bir arayüz yerine kullanılabilir, bunun yaygın bir örneği gözlemci modeli olabilir. Diğer dillerde, bir şeyin olduğuna dair bir bildirim almak istiyorsanız, aşağıdaki gibi bir şey tanımlayabilirsiniz:

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

C # 'da bu daha yaygın olarak, işleyicinin bir temsilci olduğu olaylar kullanılarak ifade edilir, örneğin:

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

Örneğin, bir listeden bir öğe kümesi seçerken, bir koşulu bir işleve geçirmeniz gerektiğinde, temsilcilerin kullanılabileceği başka bir harika yer:

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

Yukarıdakiler, aşağıdaki gibi de yazılabilen lambda sözdiziminin bir örneğidir:

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

Temsilcileri kullanmanın yararlı olabileceği başka bir yer de fabrika işlevlerini kaydetmektir, örneğin:

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

Umarım bu yardımcı olur!


Sözdizimi ile güzel örnekler .. Teşekkürler .. :)
Raghu

10

Bu konuya gerçekten geç geliyorum ama bugün delegelerin amacını anlamakta güçlük çekiyordum ve amaçlarını iyi açıkladığını düşündüğüm aynı çıktıyı veren iki basit program yazdım.

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

5

Biraz farklı bir kullanım, yansımayı hızlandırmaktır; Yani, her seferinde yansıma kullanmak yerine, Delegate.CreateDelegatebir yöntem (a MethodInfo) için (yazılan) bir delege oluşturmak ve bunun yerine bu delegeyi çağırmak için kullanabilirsiniz. Bu daha sonra çok denetler zaten yapılmış olarak, daha hızlı arama başına.

İle Expression, anında kod oluşturmak için de aynısını yapabilirsiniz - örneğin, Expressionçalışma zamanında seçilen bir tür için + operatörünü temsil eden bir + operatörünü kolayca oluşturabilirsiniz (dilin sağlamadığı jenerikler için operatör desteği sağlamak için) ; ve Expressionyazılı bir temsilciye bir derleyebilirsiniz - iş bitti.


5

Temsilciler, olayları her kullandığınızda kullanılır - çalıştıkları mekanizma budur.

Ek olarak, temsilciler LINQ sorgularını kullanmak gibi şeyler için çok kullanışlıdır. Örneğin, birçok LINQ sorgusu Func<T,TResult>, filtreleme için kullanılabilen (genellikle ) bir temsilci alır .


4

çift ​​operatörleri etkinliklere abone etme


2

Bir örnek burada görüldüğü gibi olabilir . Belirli gereksinimleri karşılayan bir nesneyi işlemek için bir yönteminiz var. Ancak, nesneyi birden çok şekilde işleyebilmek istiyorsunuz. Ayrı yöntemler oluşturmak zorunda kalmak yerine, nesneyi bir temsilciye işleyen ve temsilciyi nesneleri seçen yönteme ileten bir eşleştirme yöntemi atayabilirsiniz. Bu şekilde, tek seçici yönteme farklı yöntemler atayabilirsiniz. Bunu kolayca anlaşılır kılmaya çalıştım.


1

İş parçacıklarıyla iletişim kurmak için temsilciler kullanıyorum.

Örneğin, bir dosya indiren bir kazanma formları uygulamam olabilir. Uygulama, indirme işlemini yapmak için bir çalışan iş parçacığı başlatır (bu, GUI'nin kilitlenmesini önler). Çalışan iş parçacığı, GUI'nin durum çubuğunu güncelleyebilmesi için durum mesajlarını (örn. İndirme ilerlemesi) ana programa geri göndermek için temsilciler kullanır.



0

İlk kullanım satırı, Gözlemci / Gözlenebilir (olaylar) modelini değiştirmektir. İkincisi, Strateji modelinin güzel ve zarif bir versiyonu. Bu ilk ikisinden daha ezoterik olsa da, çeşitli başka kullanımlar da toplanabilir.


0

Etkinlikler, diğer anynch işlemleri


0

Davranışı özetlemek istediğiniz her an, ancak onu tek tip bir şekilde çağırın. Olay İşleyicileri, geri arama işlevleri, vb. Arabirimler ve yayınlar kullanarak benzer şeyler gerçekleştirebilirsiniz, ancak bazen davranışın bir türe veya nesneye bağlı olması gerekmez . Bazen özetlemeniz gereken bir davranışınız olur.


0

Tembel parametre başlatma! Önceki tüm yanıtların yanı sıra (strateji modeli, gözlemci kalıbı, vb.), Delegeler, parametrelerin tembel olarak başlatılmasını sağlar. Örneğin, oldukça fazla zaman alan ve belirli bir DownloadedObject döndüren bir Download () işleviniz olduğunu varsayalım. Bu nesne, belirli Koşullara bağlı olarak bir Depo tarafından tüketilir. Genellikle şunları yaparsınız:

storage.Store(conditions, Download(item))

Ancak, temsilcilerle (daha doğrusu lambdalar), mağazanın imzasını değiştirerek aşağıdakileri yapabilirsiniz, böylece bir Koşul ve bir Func <Item, DownloadedObject> alır ve bunu şu şekilde kullanabilirsiniz:

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

Bu nedenle, depolama, temsilciyi yalnızca gerekirse değerlendirerek Koşullara bağlı olarak indirme işlemini gerçekleştirecektir.


Küçük nokta, ancak "daha doğrusu lambdas" - C # 2.0'da anonim bir yöntemle aynısını yapabilirsiniz, ancak daha ayrıntılı olacaktır: delege (ItemType öğesi) {[dönüş] İndir (öğe);}
Marc Gravell

Elbette, LINQ ile aynı: lambdalar, delegeler için sözdizimsel şekerden başka bir şey değildir. Delegeleri daha erişilebilir hale getirdiler.
Santiago Palladino

Lambdalar, temsilcilerin yanı sıra ifade ağaçlarına dönüştürülebildikleri için delegelerden biraz daha fazlasıdır.
Jon Skeet

Lambdalar, temsilcilerden tamamen farklı olan İfadeler için de derlenebilir . Ancak örneğiniz, bir anon yönteminden kullanılabilen Func <,> kullandı. İfadeleri C # 2.0'da yazmak son derece zahmetli olurdu.
Marc Gravell


0

Array.Sort (T [] dizisi, Karşılaştırma karşılaştırması), List.Sort (Karşılaştırma karşılaştırması), vb. İçindeki karşılaştırma parametresi


0

Bildiğim kadarıyla delegeler işlev işaretçilerine dönüştürülebilir. Bu, işlev işaretçileri alan yerel kodla birlikte çalışırken hayatı ÇOK kolaylaştırır, çünkü orijinal programcı bunun gerçekleşmesi için herhangi bir hazırlık yapmamış olsa bile, etkin bir şekilde nesne yönelimli olabilirler.


0

Temsilciler, bir yöntemi referansıyla çağırmak için kullanılır. Örneğin:

  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();
        }
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.