いつC#でデリゲートを使用しますか?[閉まっている]


101

C#でデリゲートをどのように使用しますか?


2
.NET型システムのデリゲートまたはC#デリゲート構文を意味しますか?「ラムダ式構文ではなくデリゲート構文をいつ使用するか」または「クラス/インターフェース/仮想メソッドなどではなくデリゲートをいつ使用するか」という意味ですか?
ニキ

回答:


100

C#にラムダ式と無名メソッドができたので、デリゲートをさらに使用します。C#1では、ロジックを実装するために常に個別のメソッドが必要でしたが、デリゲートを使用しても意味がありませんでした。最近、私はデリゲートを使用しています:

  • イベントハンドラー(GUIなどの場合)
  • 開始スレッド
  • コールバック(非同期APIなど)
  • LINQおよび類似(List.Findなど)
  • 内部に特殊なロジックを含む「テンプレート」コードを効果的に適用したい他の場所(デリゲートが特殊化を提供する場所)

プッシュLINQの「プッシュ」に言及する価値はありますか?
Marc Gravell

3
混乱を招くことなく、簡単に説明できるかわかりません:)(おそらく、イベントハンドラー、LINQ、およびtemplatyビットでカバーされていると思います!
Jon Skeet

1
最初の文はあまり意味がありません。
senfo

3
私はあなたが何を言おうとしているのかを知っていますが、「C#にラムダ式と匿名メソッドがあるので、デリゲートをはるかに使用するようになりました」と読みやすくなります。私はつまらないことを知っていますが、意味が理解される前に、その文を実際に数回読まなければなりませんでした。
senfo

4
勇敢なスキート氏に挑戦するために大胆に+1 ;-)
インドラ2010年

29

デリゲートは多くの目的に非常に役立ちます。

そのような目的の1つは、データのシーケンスをフィルタリングするためにそれらを使用することです。このインスタンスでは、1つの引数を受け入れ、デリゲート自体の実装に応じてtrueまたはfalseを返す述語デリゲートを使用します。

これはばかげた例です-あなたはこれからもっと役に立つものを外挿できると確信しています:

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)この方法は、デリゲートです。Whereはデリゲートをパラメーターとして受け取ります。デリゲートに.Where(delegate)なるメソッドにメソッド名を渡すと、デリゲートは関数ポインタに過ぎないためです。inMyFamilyはブール型を返すため、実際には述語と見なされます。述語はブール値を返す単なるデリゲートです。
Landon Poch

4
「述語はブール値を返す単なるデリゲートです。」+1
daehaai

@LandonPochそのコメントは、より適切に回答に配置されたでしょう。私は初心者なので、どこにあるのかわからなかった。ありがとう。
Eakan Gopalakrishnan 2014

@Eakan、私はメインの質問(デリゲートをいつ使用しますか)には本当に答えていなかったので、代わりにコメントとして残しました。
Landon Poch 14

14

別の興味深い答えが見つかりました:

同僚が私にこの質問をしました-.NETのデリゲートのポイントは何ですか?私の答えは非常に短く、彼がオンラインで見つけられなかったものです:メソッドの実行を遅らせるためです。

ソース: LosTechies

LINQが行っているように。


+1 ..そのように考えていませんでした。良い点
Luke101

12

デリゲートを使用して、関数型の変数とパラメーターを宣言できます。

「リソース借用」パターンを考えてみましょう。リソースの作成とクリーンアップを制御しながら、クライアントコードがその間にリソースを「借用」できるようにします。

これはデリゲート型を宣言します。

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

このシグネチャに一致する任意のメソッドを使用して、このタイプのデリゲートをインスタンス化できます。C#2.0では、これは暗黙的に、メソッドの名前を使用するだけでなく、匿名メソッドを使用して行うことができます。

このメソッドは、タイプをパラメーターとして使用します。デリゲートの呼び出しに注意してください。

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

この関数は、次のように匿名メソッドで呼び出すことができます。無名メソッドは、それ自体の外部で宣言された変数を使用できることに注意してください。これは非常に便利です(例は少し不自然ですが)。

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

多くの場合、デリゲートは1つのメソッドとのインターフェースの代わりに使用できます。これの一般的な例は、オブザーバーパターンです。他の言語では、何かが起こったという通知を受け取りたい場合は、次のように定義します。

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

C#では、これはより一般的には、ハンドラーがデリゲートであるイベントを使用して表現されます。次に例を示します。

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

リストから項目のセットを選択するときなど、述語を関数に渡す必要がある場合にデリゲートを使用するもう1つの優れた場所:

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

上記はラムダ構文の例であり、次のように記述することもできます。

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

デリゲートを使用すると便利なもう1つの場所は、ファクトリ関数を登録することです。次に例を示します。

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

これが役に立てば幸いです!


構文の良い例..ありがとう.. :)
Raghu

10

私は本当に遅い時期にやって来ますが、今日のデリゲートの目的を理解するのに苦労していて、彼らの目的をうまく説明していると思う同じ出力を与える2つの簡単なプログラムを書きました。

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

少し異なる使い方は、反射を高速化することです。つまり、毎回リフレクションを使用する代わりに、を使用Delegate.CreateDelegateしてメソッド(a MethodInfo)への(型付き)デリゲートを作成し、代わりにそのデリゲートを呼び出すことができます。これは、ある多くのチェックはすでに行われているので、呼び出しごとに速くなります。

を使用Expressionすると、同じようにその場でコードを作成することもできます。たとえば、Expression実行時に選択された型の+演算子を表すを簡単に作成できます(言語が提供しないジェネリックの演算子サポートを提供するため) ; そしてExpression、型付きデリゲートにコンパイルできます-仕事は完了です。


5

デリゲートは、イベントを使用するときにいつでも使用できます。これがデリゲートが機能するメカニズムです。

さらに、デリゲートは、LINQクエリの使用などに非常に役立ちます。たとえば、多くのLINQクエリは、Func<T,TResult>フィルタリングに使用できるデリゲート(多くの場合)を取ります。


4

イベントハンドラをイベントにサブスクライブする


2

例はここに見られるようになるかもしれません。特定の要件を満たすオブジェクトを処理するメソッドがあります。ただし、オブジェクトを複数の方法で処理できるようにする必要があります。個別のメソッドを作成する代わりに、オブジェクトを処理する一致するメソッドをデリゲートに割り当て、オブジェクトを選択するメソッドにデリゲートを渡すだけです。これにより、1つのセレクターメソッドに異なるメソッドを割り当てることができます。これをわかりやすくするようにしました。


1

私はデリゲートを使用してスレッドと通信します。

たとえば、ファイルをダウンロードするWinフォームアプリがあるとします。アプリは、ダウンロードを行うためにワーカースレッドを開始します(これにより、GUIがロックするのを防ぎます)。ワーカースレッドはデリゲートを使用してステータスメッセージ(ダウンロードの進行状況など)をメインプログラムに送り返すので、GUIはステータスバーを更新できます。



0

使用法の最初の行は、Observer / Observable(events)パターンを置き換えることです。2つ目は、Strategyパターンのエレガントなバージョンです。他のさまざまな使用法を収集できますが、これらの最初の2つよりも難解です。


0

イベント、その他のエニッチ操作


0

動作をカプセル化したいが、それを統一された方法で呼び出したいとき。イベントハンドラー、コールバック関数など。インターフェイスとキャストを使用して同様のことを実行できますが、動作が必ずしもタイプオブジェクトに関連付けられているとは限りません。カプセル化する必要のある動作がある場合もあります。


0

遅延パラメーターの初期化!以前のすべての回答(戦略パターン、オブザーバーパターンなど)に加えて、デリゲートを使用すると、パラメーターの遅延初期化を処理できます。たとえば、かなり時間がかかり、特定のDownloadedObjectを返す関数Download()があるとします。このオブジェクトは、特定の条件に応じてストレージによって消費されます。通常、次のようにします。

storage.Store(conditions, Download(item))

ただし、デリゲート(より正確には、ラムダ)では、ストアの署名を変更して、ConditionとFunc <Item、DownloadedObject>を受け取り、次のように使用することで、次のことができます。

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

したがって、ストレージはデリゲートを必要な場合にのみ評価し、条件に応じてダウンロードを実行します。


細かい点ですが、「より正確には、ラムダ」です。C#2.0の無名メソッドを使用すると同じことができますが、より冗長になります
。delegate

もちろん、LINQと同じです。ラムダはデリゲートの構文糖にすぎません。彼らはデリゲートをよりアクセスしやすくしました。
サンティアゴパラディーノ

ラムダはデリゲートだけでなく式ツリーにも変換できるため、デリゲートだけではありません。
Jon Skeet、

ラムダは、デリゲートとは完全に異なる式にコンパイルすることもできます。しかし、あなたの例では、anonメソッドから使​​用できるFunc <、>を使用しました。C#2.0で式を記述するのは非常に困難です。
Marc Gravell



0

私の知る限り、デリゲートは関数ポインターに変換できます。これにより、元のプログラマーがそれを実現するための準備をしていなかったとしても、関数指向のオブジェクトコードを効果的にオブジェクト指向にすることができるので、関数ポインターを取得するネイティブコードと相互運用するときに、生活がはるかに簡単になります。


0

デリゲートは、参照によってメソッドを呼び出すために使用されます。例えば:

  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();
        }
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.