ホームページ > バックエンド開発 > C#.Net チュートリアル > C# のデリゲート インスタンス コードの詳細な説明 (画像とテキスト)

C# のデリゲート インスタンス コードの詳細な説明 (画像とテキスト)

黄舟
リリース: 2017-03-29 11:40:43
オリジナル
1695 人が閲覧しました

この記事では主にC#における委任に関する関連知識を紹介します。一定の参考値がありますので、以下のエディターで見てみましょう

コミッショニングはあまり理解しにくいですが、仕事ではよく使われており、人々に愛されていると感じさせます。憎しみの感情に悩まされたことのある人は多いと思います。

委任に関して、C 言語を学習したことがある方は、すぐに 関数ポインタ を思い浮かべるでしょう。

委任とは何ですか? C# ではデリゲートはタイプセーフであり、同じ署名メソッドを使用して 1 つ以上の関数ポインターをサブスクライブできます。委任は関数をパラメータとして渡すことができ、その実際の意味は、他の人にあなたの代わりに行動させることです。デリゲートは、関数へのポインターと見なすことができます。integer は整数 変数 によって指すことができ、object はオブジェクト変数によって指すことができ、関数もデリゲートによって指すことができます。変数。デリゲート型を 1 つのメソッドのみを定義する

インターフェイス

として考えることができ、デリゲートのインスタンスはそのインターフェイスを実装するオブジェクトとして考えることができます。 デリゲートを使用するには、次の 4 つの条件を満たす必要があります:

    は、実行されるコードを含むメソッドを持っている必要があります。
  • はデリゲートインスタンスを呼び出す(呼び出す)必要があります。

  • デリゲートの宣言
  • デリゲートの宣言方法: デリゲートの戻り値の型 デリゲートの型名(パラメータ)

  • デリゲートの宣言はインターフェースメソッドの宣言と基本的に同じですが、次の点が異なります。戻り値の型 A デリゲート キーワードの前に追加のキーワードがあります。また、デリゲートは他の人がいつでも呼び出すことができるため、通常、パブリック型として宣言されます。
  • 委任の本質も一種です。クラスはインスタンス化でき、デリゲートもインスタンス化できることを宣言します。

  • 委任には次の 4 つのタイプがあります:
//1.无参数无返回值
    public delegate void NoParaNoReturnEventHandler();
    //2.有参数无返回值
    public delegate void WithParaNoReturnEventHandler(string name);
    //3.无参数有返回值
    public delegate string NoParaWithReturnEventHandler();
    //4.有参数有返回值
    public delegate string WithParaWithReturnEventHandler(string name);
ログイン後にコピー

コードで操作を実行したいが、操作の詳細がわからない場合は、通常は委任を使用できます。たとえば、Thread クラスが新しいスレッドで何を実行するかを知っている唯一の理由は、新しいスレッドの開始時に ThreadStart または ParameterizedThreadStart デリゲート インスタンスが提供されるからです。

Thread th = new Thread(Test);
th.Start();
public Thread(ThreadStart start);
public delegate void ThreadStart();
ログイン後にコピー
ThreadStart はパラメーターも戻り値も持たないデリゲートです。

    static void Test()
    {
      Console.WriteLine("线程方法");
    }
ログイン後にコピー

この Test メソッドの関数シグネチャは、デリゲート ThreadStart の関数シグネチャと一致している必要があります。

デリゲートの呼び出し

は、まずデリゲートをインスタンス化してから呼び出す必要があります。

関数の署名とデリゲートの署名は一貫している必要があります。

NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo;,

コンパイラは new の実行に役立ちますが、これは関数呼び出しになるため、

NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo(); として記述することはできません。

#region 无返回值委托调用
    public static void Show()
    {
      //实例化委托
      NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = new NoParaNoReturnEventHandler(ConsoleInfo);
      //NoParaNoReturnEventHandler _NoParaNoReturnEventHandler = ConsoleInfo; //简写
      //委托调用 通过Invoke()调用,或者可以直接省略
      _NoParaNoReturnEventHandler.Invoke();
      //_NoParaNoReturnEventHandler();
    }
    private static void ConsoleInfo()
    {
      Console.WriteLine("无参数无返回值的函数调用");
    } 
    #endregion
ログイン後にコピー

委任がなければ、非同期は存在しません。

_NoParaNoReturnEventHandler.BeginInvoke(null,null); //非同期呼び出し

デリゲートを使用する理由メソッドを直接呼び出すことができるのに、なぜデリゲートを介して呼び出す必要があるのでしょうか?委任とはどういう意味ですか?

分離され、変更は受け付けられませんが、拡張はオープンです。論理的な分離。

デリゲートは、関数の親クラス、またはメソッドのプレースホルダーとして理解できます。

コードを見てみましょう。英語を話すメソッドと中国語を話すメソッドの 2 つがあり、これら 2 つのメソッドの関数シグネチャが同じであるとします。

public static void SayChinese(string name)
    {
      Console.WriteLine("你好," + name);
    }
    public static void SayEnglish(string name)
    {
      Console.WriteLine("hello," + name);
    }
ログイン後にコピー

それでは、外部から呼び出すとき、

  MyDelegate.SayChinese("张三");
  MyDelegate.SayEnglish("zhangsan");
ログイン後にコピー

これら 2 つの異なるメソッドを呼び出したい場合、異なる呼び出しコードを記述する必要がありますか

メソッドを 1 つだけ呼び出すことはできますか?コードを次のように変更します。

public static void Say(string name,WithParaNoReturnEventHandler handler)
    {
      handler(name);
    }
   public static void SayChinese(string name)
    {
      Console.WriteLine("你好," + name);
    }
    public static void SayEnglish(string name)
    {
      Console.WriteLine("hello," + name);
    }
ログイン後にコピー

このようにして、Say メソッドが 1 つだけ呼び出されます。

なんと呼びますか?呼び出しメソッドは以下の 3 つです。

      WithParaNoReturnEventHandler _WithParaNoReturnEventHandler = new WithParaNoReturnEventHandler(MyDelegate.SayChinese);
      MyDelegate.Say("张三",_WithParaNoReturnEventHandler);
      MyDelegate.Say("张三", delegate(string name) { Console.WriteLine("你好," + name); }); //匿名方法
      MyDelegate.Say("张三", (name) => { Console.WriteLine("你好," + name); }); //lambda表达式
ログイン後にコピー

上記のコードでは複数の呼び出しメソッドが使用されており、これらの呼び出しメソッドは C# のアップグレードに伴って継続的に最適化されます。 1 つ目は C# 1.0 で存在した従来の呼び出しメソッドで、2 つ目は C# 2.0 での匿名メソッド呼び出しメソッドです。いわゆる匿名メソッドは、メソッドを呼び出すときに匿名メソッドを使用するのが最適です。呼び出されるのは 1 回だけです。 C#3 のラムダ式。実際、ジェネリック デリゲートもサポートされており、.NET 3.5 ではさらに一歩進んで、指定された型の複数のパラメーターを取得し、指定された型の別の値を返すことができる Func と呼ばれる一連のジェネリック デリゲート型が導入されています。

ラムダ式

ラムダ式の本質はメソッド、つまり匿名メソッドです。

メソッド本体に 1 行しかなく、戻り値がない場合は、中括弧とセミコロンを削除することもできます。

MyDelegate.Say("张三", (name) => Console.WriteLine("你好," + name));

如果方法体只有一行,有返回值,可以去掉大括号和return。

WithParaWithReturnEventHandler _WithParaWithReturnEventHandler = (name)=>name+",你好";

从.NET3.5开始,基本上不需要我们自己来申明委托了,因为系统有许多内置的委托。

Action和Func委托,分别有16个和17个重载。int表示输入参数,out代表返回值,out参数放置在最后。

Action表示无返回值的委托,Func表示有返回值的委托。因为方法从大的角度来分类,也分为有返回值的方法和无返回值的方法。

也就是说具体调用什么样的方法,完全由调用方决定了,就有了更大的灵活性和扩展性。为什么这么说,如果我有些时候要先说英语再说汉语,有些事时候要先说汉语再说英语,如果没有委托,我们会怎么样实现?请看如下代码:

public static void SayEnglishAndChinese(string name)
    {
      SayEnglish(name);
      SayChinese(name);
    }
    public static void SayChineseAndEnglish(string name)
    {
      SayChinese(name);
      SayEnglish(name);
    }
ログイン後にコピー

如果又突然要添加一种俄语呢?被调用方的代码又要修改,如此循环下去,是不是要抓狂了?随着不断添加新语种,代码会变得越来越复杂,越来越难以维护。这样的代码耦合性非常高,是不合理的,也就是出现了所谓的代码的坏味道,你可以通过设计模式(如观察者模式等),在不使用委托的情况下来重构代码,但是实现起来是非常麻烦的,要写很多更多的代码...

委托可以传递方法,而这些方法可以代表一系列的操作,这些操作都由调用方来决定,就很好扩展了,而且十分灵活。我们不会对已有的方法进行修改,而是只以添加方法的形式去进行扩展。

可能有人又会说,我直接在调用方那里来一个一个调用我要执行哪些方法一样可以实现这样的效果啊?

可你有没有想过,你要调用的是一系列方法,你根本无法复用这一系列的方法。使用委托就不一样了,它好比一个方法集合的容器,你可以往里面增减方法,可以复用的。而且使用委托,你可以延时方法列表的调用,还可以随时对方法列表进行增减。委托对方法进行了再一次的封装。

总结:也就是当你只能确定方法的函数签名,无法确定方法的具体执行时,为了能够更好的扩展,以类似于注入方法的形式来实现新增的功能,就能体现出委托的价值。

委托和直接调用函数的区别:用委托就可以指向任意的函数,哪怕是之前没定义的都可以,而不用受限于哪几种。

多播委托

组合的委托必须是同一个类型,其相当于创建了一个按照组合的顺序依次调用的新委托对象。委托的组合一般是给事件用的,用普通委托的时候很少用。

通过+来实现将方法添加到委托实例中,-来从委托实例中进行方法的移除。

+和-纯粹是为了简化代码而生的,实际上其调用的分别是Delegate.Combine方法和Delegate.Remove。

如果委托中存在多个带返回值的方法,那么调用委托的返回值是最后一个方法的返回值。

public static void MultipleShow()
    {
      //多播委托
      NoParaWithReturnEventHandler _NoParaWithReturnEventHandler = new NoParaWithReturnEventHandler(GetDateTime);
      _NoParaWithReturnEventHandler += GetDateTime;
      Console.WriteLine(_NoParaWithReturnEventHandler());
    }
    public static string GetDateTime()
    {
      return string.Format("今天是{0}号。", DateTime.Now.Day.ToString());
    }
ログイン後にコピー

委托总结:

  • 委托封装了包含特殊返回类型和一组参数的行为,类似包含单一方法的接口;

  • 委托类型声明中所描述的类型签名决定了哪个方法可用于创建委托实例,同时决定了调用的签名;

  • 为了创建委托实例,需要一个方法以及(对于实例方法来说)调用方法的目标;

  • 委托实例是不易变的,就像String一样;

  • 每个委托实例都包含一个调用列表——一个操作列表;

  • イベントはデリゲートインスタンスではなく、単に add/remove メソッドのペアです (property の getter/assignment メソッドと同様)。

一般的な使用シナリオ: フォーム値の転送、スレッド開始時のバインディングメソッド、ラムダ式、非同期など。

現実の例: 今、誰もが電車のチケットを手に入れているというのは本当ではないでしょうか? クラウドを使用してチケットを手に入れることは、チケットを自分で直接購入することも、クラウドでチケットをホストすることもできます。チケットを自分で取得する場合は、チケットを購入するときに常に更新し、注文時に認証コードを入力する必要があります。チケットを取得するためにクラウドを使用する場合は、では、チケットをリリースする前に事前にチケット取得情報を入力するだけで済み、チケットは自動的に発行されます。クラウド チケット取得がチケットの取得にどのように役立つかを知る必要はありません。 。同じ時刻と列車番号を委任インスタンスにすることができ、多くの人がこの委任インスタンスを使用してチケットを取得します。

以上がC# のデリゲート インスタンス コードの詳細な説明 (画像とテキスト)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート