委托分配是否会在 C# 中创建一个新副本?

lys*_*cid 4 .net c# mono garbage-collection memory-management

我读了一篇关于 C# 和性能注意事项的文章(这里

在文章中,据说委托分配会触发内存分配,例如:

每个像“Func fn = Fn”这样的局部变量赋值都会在堆上创建一个委托类 Func 的新实例

我想知道这是否属实,如果是 - 如何实施?我不熟悉引用分配可以在 C# 中触发额外内存分配的任何方式。

xan*_*tos 5

文章是对的。很容易测试:

static void Main(string[] args)
{
    Action<string[]> main = Main;
    Action<string[]> main2 = Main;
    Console.WriteLine(object.ReferenceEquals(main, main2)); // False
}
Run Code Online (Sandbox Code Playgroud)

http://ideone.com/dgNxPn

如果您查看生成的 IL 代码http://goo.gl/S47Wfy,很明显会发生什么:

    IL_0002: ldftn void Test::Main(string[])
    IL_0008: newobj instance void class [mscorlib]System.Action`1<string[]>::.ctor(object, native int)
    IL_000d: stloc.0
    IL_000e: ldnull

    IL_000f: ldftn void Test::Main(string[])
    IL_0015: newobj instance void class [mscorlib]System.Action`1<string[]>::.ctor(object, native int)
    IL_001a: stloc.1
Run Code Online (Sandbox Code Playgroud)

所以有两个 newobj instance void class [mscorlib]System.Action1::.ctor(object, native int)`

请注意,您是对的,这是违反直觉的:

public class TestEvent
{
    public event Action Event;

    public TestEvent()
    {
        Action d1 = Print;
        Action d2 = Print;

        // The delegates are distinct
        Console.WriteLine("d1 and d2 are the same: {0}", object.ReferenceEquals(d1, d2));

        Event += d1;
        Event -= d2;

        // But the second one is able to remove the first one :-)
        // (an event when is empty is null)
        Console.WriteLine("d2 was enough to remove d1: {0}", Event == null);
    }

    public void Print()
    {
        Console.WriteLine("TestEvent");
    }
}
Run Code Online (Sandbox Code Playgroud)

events 为例,您可以使用“等效但不相同”的委托来删除另一个委托,如示例所示。见https://ideone.com/xeJ6LO

  • @lysergic-acid https://msdn.microsoft.com/en-us/library/ms173176.aspx 在 C# 1.0 和 1.2 中,你必须明确地做一个 `new MyDelegate(function)`。然后在 C# 2.0 中,他们将其隐式化。我还要补充一点,即使那个表单也是伪造的,因为委托的构造函数的签名是`MyDelegate(object, IntPtr)`,其中`object` 是对委托的“目标”对象的引用(` this` 将被委托方法使用),`IntPtr` 是方法的地址。如果您观察 IL 代码中如何调用 `newobj`,您可以看到它(请参阅第二个代码块) (2认同)