15

Action で Delegate を初期化する 2 つの異なる方法を見つけました。

新しいアクションを作成するか、Action にキャストします。

Delegate foo = new Action(() => DoNothing(param));
Delegate bar = (Action)(() => DoNothing(param));

この2つの構文に違いはありますか?

どちらが優れているのか、その理由は?

この例でデリゲートが使用されているのは、ラムダ式を使用して BeginInvoke や Invoke などのメソッドを呼び出すのに構文が便利であり、ラムダ式をアクションにキャストすることが重要であるためです。

static main 
{
    Invoke((Action)(() => DoNothing())); // OK
    Invoke(new Action(() => DoNothing())); // OK
    Invoke(() => DoNothing()); // Doesn't compil
}

private static void Invoke(Delegate del) { }

しかし興味深いのは、コンパイラがこれを承認したことです:

Action action = () => DoNothing();
Invoke(action);
4

3 に答える 3

13

この 2 つの命令に違いはありません。both 命令では、Action の新しいインスタンスが作成されます。

以下の IL コードはこれを確認しているようです。

コンソール プログラム:

class Program
{
    static void Main(string[] args)
    {
        Delegate barInit = (Action)(() => DoNothing());
        Delegate fooInit = new Action(() => DoNothing());
    }

    private static void DoNothing() { }
}

IL コード :

// First instruction
IL_0000: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2'
IL_0005: brtrue.s IL_0018

IL_0007: ldnull
IL_0008: ldftn void CodeMachineTest.Program::'<Main>b__0'()

// Create a new Action instance for the instruction (Action)(() => DoNothing())
IL_000e: newobj instance void [mscorlib]System.Action::.ctor(object, native int)

IL_0013: stsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2'

IL_0018: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate2'
IL_001d: pop

// Second instruction
IL_001e: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_0023: brtrue.s IL_0036

IL_0025: ldnull
IL_0026: ldftn void CodeMachineTest.Program::'<Main>b__1'()
IL_002c: newobj instance void [mscorlib]System.Action::.ctor(object, native int)
IL_0031: stsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3'

IL_0036: ldsfld class [mscorlib]System.Action CodeMachineTest.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_003b: pop
IL_003c: ret
于 2013-05-02T01:56:38.440 に答える
2

私の考えでは、違いはありません。

new Action(() => DoNothing(param));

これは単に新しいアクションを作成し、ラムダ式を渡します。コンパイラはそれを処理し、すべてがうまく接続されていることを確認します。

(Action)(() => DoNothing(param));

これが機能するのは、このようなラムダ メソッドは値を返さず、パラメーターをとらないためです。そのため、コンパイラーは、デリゲート システムを通過するという理由でアクションに "マップ可能" であることを確認できます。

それらは多かれ少なかれ同じであり、コンパイラの最適化の種類に応じて、どちらがよりパフォーマンスが高いかを言うのは難しいです。おそらく、パフォーマンスをテストして自分で確認する必要がありますか?

これは興味深い質問であり、委任システムと、Linq と式がどのように適合するかについての調査です。

new Func<string>(() => "Boo!");

ほぼ同等です:

(Func<String>)() => "Boo!";

私が知る限り、それらは両方ともデリゲート システムInvoke()などを通過することになると思いますが、パフォーマンスをテストして結果を共有していただければ興味深いと思います。

于 2013-05-02T00:42:18.043 に答える