7

デリゲートのシグネチャは、デリゲートするメソッドのシグネチャと一致する必要があるという点で、デリゲートについてゆっくりと頭を悩ませています。

ただし、次のコードを確認してください。

public static void Save()
{
    ThreadStart threadStart = delegate
    {
        SaveToDatabase();
    };
    new Thread(threadStart).Start();
}

private static void SaveToDatabase() { }

voidデリゲートが返されるため(それが何であるか) 、この時点で困惑していますSaveToDatabase()が、明らかに返されていThreadStartます...またはそれですか?

独自のデリゲートを作成する場合、デリゲートは の戻り値の型と一致するように void でなければならないため、これを実現する方法がわかりませんSaveToDatabase()。しかし、それはできません。それはタイプになりますThreadStart

私の質問は、私が完全に誤解したのか、それとも .NET の策略によって可能になったのかということです。このメソッドを書きたいが、独自のデリゲートを作成したい場合、どうすればよいでしょうか?

4

4 に答える 4

5

「デリゲート」という言葉は少し乱用されています。クラスとオブジェクトを使用すると簡単です。「クラス」はオブジェクトの設計図のようなものです。「オブジェクト」はメモリ内の実際のインスタンスであり、クラスの設計図に従います。

デリゲートについても同じ言葉を使用しているため、混乱していると思います。次のコードを検討してください。

class Main
{
    public delegate int DelegateType(string x);
    public int SomeFunction(string y) { return int.Parse(y)*2; }
    public void Main()
    {
        DelegateType delegateInstance = null;
        delegateInstance = SomeFunction;
        int z = delegateInstance("21");
        Console.WriteLine(z);
    }
}

このコードは「42」を出力します。

DelegateTypeデリゲートの型です。クラスがオブジェクトの設計図であるように、デリゲートは関数の設計図です。

そのため、後でdelegateInstance、タイプの変数という名前を作成しますDelegateType。その変数には、単一の文字列パラメーターを取り、整数を返すANY関数を割り当てることができます。関数の結果ではなく、関数自体を割り当てたことに注意してください。delegateInstance変数がその関数のシノニムになったようです。実際、後で行を示したdelegateInstanceように、関数を呼び出すために使用できるようになりました! あたかもdelegateInstance関数そのものであるかのように。しかし、それは変数であるため、通常変数で行うのと同じことをすべて行うこともできます-変数をパラメーターとして他の関数に渡したり、他の関数から返すことさえできます(関数を返す関数! !)

では、あなたを困惑させたコードを見てみましょう。

public static void Save()
{
    ThreadStart threadStart = delegate
    {
        SaveToDatabase();
    };
    new Thread(threadStart).Start();
}

private static void SaveToDatabase() { }

最初に気付くのは、anonymous delegate. 用語の別の誤用。コンパイルすると、次のようになります。

public static void Save()
{
    ThreadStart threadStart;
    threadStart = __ASDASDASD6546549871;
    var tmp = new Thread(threadStart);
    tmp.Start();
}

private static void SaveToDatabase() { }

private void __ASDASDASD6546549871()
{
    SaveToDatabase();
}

匿名関数は、実際にはランダムな名前を持つ完全に通常の関数に変換され、その関数がthreadStart変数に割り当てられていることに注意してください。

したがって、これは上記の例とまったく同じです。DelegateTypeThreadStartdelegateInstanceに置き換えるだけthreadStartですSomeFunction__ASDASDASD6546549871

それは今意味がありますか?

于 2012-12-10T14:40:38.770 に答える
4

デリゲートがvoidを返すため(これがSaveToDatabase()であるため)、この時点で困惑していますが、明らかにThreadStartを返しています...それともそうですか?

自分のデリゲートを正しくする場合、デリゲートはSaveToDatabase()の戻りタイプと一致するように無効にする必要があるため、これを実現する方法がわかりませんが、スレッドスタートタイプであるため、そうすることはできません。

ThreadStartはデリゲートとして定義されています。実際、それは次のように定義されています

public delegate void ThreadStart();

したがって、コードはデリゲートまたはを返しませんThreadStartThreadStartデリゲート定義に一致する関数を定義しているだけです。Threadコンストラクターは、関数を指す変数として定義したデリゲートを想定していThreadStartます。threadStartSaveToDatabase

私はデリゲートを古いC++用語の「関数ポインタ」と考える傾向があります。デリゲートを使用すると、別の関数にパラメーターとして渡す必要のある関数の種類(パラメーターと戻り値のタイプ)を指定できます。

私の質問は、私は完全に誤解されているのか、それとも.NETのトリックによって可能になったのかということです。このメソッドを作成したいが、独自のデリゲートを作成したい場合、どうすればよいですか?

誤解されたのではないかと思います。ただし、この質問に具体的に答えるには、作成するメソッドは、デリゲートタイプ(この場合はThreadStart)で指定された定義と一致する必要があります。そのメソッド定義はvoid、パラメーターを返さずに受け入れる必要があります。メソッドはこのデリゲートSaveToDatabaseタイプと一致するため、作成するのに適切なデリゲートメソッドです。

于 2012-12-10T14:30:54.580 に答える
2

MSDNから

デリゲートは、メソッドを参照する型です。デリゲートにメソッドが割り当てられると、そのメソッドとまったく同じように動作します。デリゲートメソッドは、次の例のように、パラメーターと戻り値を使用して、他のメソッドと同じように使用できます。

public delegate int PerformCalculation(int x, int y);

したがって、デリゲートのリターンタイプは、デリゲートしているメソッドのリターンタイプと一致します。

戻り値のタイプとパラメーターで構成される、デリゲートの署名に一致する任意のメソッドをデリゲートに割り当てることができます。これにより、プログラムでメソッド呼び出しを変更したり、新しいコードを既存のクラスにプラグインしたりすることができます。デリゲートの署名を知っている限り、独自のデリゲートされたメソッドを割り当てることができます。

于 2012-12-10T14:31:08.480 に答える
2

管理されたサブプロセスを実行する場合、実行されるメソッドはThreadStartまたはParameterizedThreadStartで表されますSaveToDatabaseが、タイプではなくシグネチャでvoid実行されます。voidThreadStart

MSDN の例:

class Test
{
    static void Main() 
    {
        // To start a thread using a static thread procedure, use the
        // class name and method name when you create the ThreadStart
        // delegate. Beginning in version 2.0 of the .NET Framework,
        // it is not necessary to create a delegate explicityly. 
        // Specify the name of the method in the Thread constructor, 
        // and the compiler selects the correct delegate. For example:
        //
        // Thread newThread = new Thread(Work.DoWork);
        //
        ThreadStart threadDelegate = new ThreadStart(Work.DoWork);
        Thread newThread = new Thread(threadDelegate);
        newThread.Start();

        // To start a thread using an instance method for the thread 
        // procedure, use the instance variable and method name when 
        // you create the ThreadStart delegate. Beginning in version
        // 2.0 of the .NET Framework, the explicit delegate is not
        // required.
        //
        Work w = new Work();
        w.Data = 42;
        threadDelegate = new ThreadStart(w.DoMoreWork);
        newThread = new Thread(threadDelegate);
        newThread.Start();
    }
}

class Work 
{
    public static void DoWork() 
    {
        Console.WriteLine("Static thread procedure."); 
    }
    public int Data;
    public void DoMoreWork() 
    {
        Console.WriteLine("Instance thread procedure. Data={0}", Data); 
    }
}
于 2012-12-10T14:25:39.017 に答える