cxiでの依頼に対する理解


理解依頼は簡単な例から始まります。
金城武さんが演じた古い映画「ラベンダー」の中には、金さんがお客さんのお金を受け取って、お客さんを代表して違う人に行くというストーリーがあります。
彼の取引先は最初は中国人で、中国語だけで話します。以下のようなコード例は簡単で、すべての中国の取引先をサポートします。

public class LoveManager
{
    public void Love(string name)
    {
        Console.WriteLine(" , {0}", name);
    }
}

class Program
{
    static void Main(string[] args)
    {
        LoveManager loveManager = new LoveManager();
        loveManager.Love(" ");
    }
}
実行結果:

,
後に映画に外国人のお客さんが現れたことに気づきました。コードはこうなるべきだと思います。

// ,
public enum Language
{
    English,
    Chinese
}

public class LoveManager
{
    public void Love(string name, Language lang)
    {
        switch (lang)
        {
            case Language.Chinese:
                loveChinese(name);
                break;
            case Language.English:
                loveEnglish(name);
                break;
        }
    }

    //
    public void LoveChinese(string name)
    {
        Console.WriteLine(" , {0}", name);
    }

    //
    public void LoveEnglish(string name)
    {
        Console.WriteLine("I love you, {0}", name);
    }
}


class Program
{
    static void Main(string[] args)
    {
        LoveManager loveManager = new LoveManager();
        loveManager.Love(" ", Language.Chinese);
        loveManager.Love("Sophie Marceau", Language.English);
    }
}
実行結果:

,
I love you, Sophie Marceau
OKです。今は張曼玉さんは「愛しています。」が分かります。Sophie Marceauさんは「I love you」が分かります。英汉双语の弁明を支持しましたが、これからはフランスのお客様、ポルトガルのお客様、アラブのお客様はどうすればいいですか?各言語を拡張するには、この言語の「愛しています」を追加する以外に、列挙を拡張しなければなりません。Love Manager.Love()を拡張するのは、確かにちょっと煩わしいです。
 
C言語時代:指針
この時、C言語の中で有名な指針に言及せざるを得ません。ポインタは、関数のアドレスをパラメータとして別の関数に渡すことができます。この特性は、その後の様々な高度な言語において拡張され強化されます。まず次のCコードを見てください。

#include <stdio.h>

//
void func1(void(*p)(void)){
    printf("this is func1\r
");
    //
    p();
}

void func2(){
    printf("this is func2\r
");
}

int main() {
    // func2
    func1(func2);
    return 0;
}

実行結果:

this is func1
this is func2
NetではC言語のように関数をパラメータとして伝達して呼び出しできますか?

// , .Net Love(" ", LoveChinese);
Love("Sophie Marceau", LoveEnglish);
.Netでより完璧なソリューション:委託
Netでは、C言語のように関数をパラメータとして伝達することができるだけでなく、Netでは、タイプのセキュリティ機構とより強力な機能を提供しています。

using System;

namespace DelegateDemo
{
    //
    public delegate void LoveDelegate(string name);

    public class LoveManager
    {
        public void Love(string name, LoveDelegate loveDelegate)
        {
            loveDelegate(name);
        }

        //
        public void LoveChinese(string name)
        {
            Console.WriteLine(" , {0}", name);
        }

        //
        public void LoveEnglish(string name)
        {
            Console.WriteLine("I love you, {0}", name);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            LoveManager loveManager = new LoveManager();
            loveManager.Love(" ", loveManager.LoveChinese);
            loveManager.Love("Sophie Marceau", loveManager.LoveEnglish);
        }
    }
}

実行結果:

,
I love you, Sophie Marceau
定義依頼

public delegate void LoveDelegate(string name);
依頼についてまとめてみます。委託は方法の種類を定義し、方法を別の方法のパラメータとして伝えることができます。この方法はパラメータを動的に付与する方法で、プログラムにIf-Else文を大量に使用することを避けることができます。C〓〓では、特有のキーワードdelegateを用いて定義を依頼していますが、delegateの直後には関数署名が続きます。タイプのセキュリティを確保するために、Netの委託要求関数は、func(int p)とfunc(string p)のような同じタイプの署名を持っています。

ILDasm.exeにより、定義依頼の行コードは実際にコンパイル時に自動的に1つのクラスを生成します。このクラスを復元するなら、コードはこうなります。

public class LoveDelegate : System.MulticastDelegate
{
      //
      public LoveDelegate(Object obj, IntPtr method);

      //
      public virtual void Invoke(string name);

      //
      public virtual IAsyncResult BeginInvoke(Int32 value, AsyncCallback callback, Object obj);
      public virtual void EndInvoke(IAsyncResult result);
}

したがって、委託は実際には一つの種類であり、System.Multicast Delegateに継承されています。すべての種類を定義できるところは委託を定義することができます。
委託の構造関数

LoveManager loveManager = new LoveManager();
// ,
//LoveDelegate loveDelegate = new LoveDelegate();
LoveDelegate loveDelegate = new LoveDelegate(loveManager.LoveChinese);
loveDelegate(" ");
クラスと違って、委託は一つのパラメータを持つ構造関数を使用しなければなりません。
推論文法を依頼する

LoveManager loveManager = new LoveManager();
// :LoveDelegate loveDelegate = new LoveDelegate(loveManager.LoveChinese);
LoveDelegate loveDelegate = loveManager.LoveChinese;
loveDelegate(" ");
方法とのバインディングを依頼します。
上記の例に戻ります。ある日、富二代が金さんを見つけました。お金は問題ではないと言っています。張曼玉の下に行って、中国語で呼んでください。もう一度英語で呼んでください。

static void Main(string[] args)
{
        LoveManager loveManager = new LoveManager();
        //
        LoveDelegate delegate1;
        // ( )
        delegate1 = loveManager.LoveChinese;
        // ( )
        delegate1 += loveManager.LoveEnglish;
        delegate1(" ");
}
実行結果:

,
I love you,
複数の方法を一つの依頼に結び付けてもいいです。  -= 除去方法と依頼のバインディング。
匿名の方法
お客さんの需要はいつも千変万化しています。あるお客さんは金さんと告白したいです。中国語のほかに、英語で追加してくださいませんか?

LoveManager loveManager = new LoveManager();
LoveDelegate loveDelegate = loveManager.LoveEnglish;
loveDelegate += loveManager.LoveChinese;
loveDelegate += delegate(string name)
{
    Console.WriteLine("{0}, ?", name);
};
loveDelegate(" ");
実行結果:

I love you,

, ?
この特殊な取引先に対して匿名の方法を使いました。誰もが愛を示す時ではなく、大明湖畔の夏雨荷ということです。この特殊な取引先が一回使うので、独立した方法を定義する必要はありません。匿名の方法を使用すると符号量を低減し、コードの複雑さを低減することができる。
ラボンダ(λ)表式
C鵬3.0は匿名の方法にLambada表現を提供し、以下のコード実行結果は上記の例と完全に一致している。

LoveManager loveManager = new LoveManager();
LoveDelegate loveDelegate = loveManager.LoveEnglish;
loveDelegate += loveManager.LoveChinese;
// Lambda loveDelegate += name =>
{
    Console.WriteLine("{0}, ?", name);
};
loveDelegate(" ");
=>Lamban演算子のために、演算子の左側に匿名の方法で必要なパラメータが並べられています。
(string param 1,int param 2)
もできます
(param 1、param 2)
例のコードのようにパラメータが一つしかない場合は、括弧を外してもいいです。
param 1
Lambda表式は右側が匿名の方法でコードを実現しています。コードが1行しか実現されていない場合、かっことreturn文も削除できます。コンパイラは自動的に追加されますから。
共に学び、共に向上します。