代码之家  ›  专栏  ›  技术社区  ›  Jason Young

委托实例和方法指针有什么区别?

  •  9
  • Jason Young  · 技术社区  · 15 年前

    我认为委托实例可以与函数实例互换。

    采用以下代码:

    delegate int AddDelegate(int a, int b);
    
    AddDelegate DelegateInstance;
    
    public void DoStuff()
    {
        //I can call this without a delegate "instance":
        MethodThatTakesAdd(Add);
    
        //I can also call it WITH a delegate "instance"
        DelegateInstance = Add;
        MethodThatTakesAdd(DelegateInstance);
    }
    
    public int Add(int a, int b)
    {
        return a + b;
    }
    
    public void MethodThatTakesAdd(AddDelegate addFunction)
    {
        Console.WriteLine(addFunction(1, 2).ToString());
    }
    

    两种调用方式似乎都是等效的,如果您只使用C,您将永远看不到区别(至少到目前为止我还没有)。但是,我最近调用了这个托管代码的非托管代码,它们的处理方式不同。例如,在一个场景中,如果我直接将函数用作回调(即使我的对象实例保留在周围),我将得到错误“在垃圾收集委托上进行了回调”。使用“委托实例”可以解决问题。

    有人知道有什么区别吗?

    3 回复  |  直到 15 年前
        1
  •  13
  •   JaredPar    15 年前

    术语对应:方法组不是方法指针,更合适的术语是方法组。

    就功能而言,这两个语句是等效的。就是他们生产的 几乎 同样的IL。不同之处在于委托值的存储位置。

    在第一种情况下,将方法组add传递给直接获取sadd的方法。这将导致创建一个临时委托值,然后将其传递给接受SADD的方法。此委托值在takesadd返回方法时受到垃圾收集的影响,因为它不存储该值。

    在第二种情况下,您将委托分配给外部实例上的字段。本遗嘱 典型地 增加委托的生命周期,从而减少在PInvoke调用期间被垃圾收集的机会。

        2
  •  4
  •   Steve Guidi    15 年前

    委托是可调用的类,具有类似的 行为 函数指针。委托在内部存储要调用的函数的地址(即函数指针),但也提供其他功能,如多重转换和存储调用列表;您基本上可以用一个委托实例调用多个具有相同签名的函数,如下所示。

    public void DoStuff()
    {
        DelegateInstance += Add;
        DelegateInstance += AnotherAdd;
        DelegateInstance += YetAnotherAdd;
    
        // Invoke Add(100, 200), AnotherAdd(100, 200), and YetAnotherAdd(100, 200)
        DelegateInstance(100, 200);
    }
    

    关于你的笔记关于 MethodThatTakesAdd(Add) MethodThatTakesAdd(DelegateInstance) , 如果您查看C编译器为该行生成的MSIL 采用的方法(添加) ,您将注意到编译器正在创建委托并包装 Add() 你的方法。

        3
  •  0
  •   3Dave    15 年前

    当代表在C语言中提供同义功能作为C或C++中的函数指针时,有显著的差异。其中的关键是 委托是一个类 ,不是指针。

    简而言之,将委托强制转换为指针不会给您提供对函数或方法的引用,因此不能使用它从非托管代码中引用来调用方法。