C# 的 delegate 在创建实例时一定要new吗? 为什么我不new也可以啊?如下语句: [ComVisible(true)]
    public class EventDisp
    {
        public EventDisp( FnEvent fnEvent)
        {
            _fnEvent = fnEvent ;//注意这里没有用 new FnEvent( fnEvent ) 的方法
        }
        #region Private Variable
        public delegate void FnEvent();
        FnEvent _fnEvent;
        #endregion        IHTMLDocument2 _doc2;
        [DispId(0)]
        public void Event()
        {
            _fnEvent();
        }
    }创建一个IDispatch的对象, 构造函数接受一个函数指针.
然后我调用的时候是这样干的:
 Document2.onclick = new EventDisp( _OnClick );
程序也完全正常,没有发生问题.所以我很疑惑,为啥?
谢谢大家!

解决方案 »

  1.   

    这是c#编译器帮你简化了。当它翻译为msil时,仍然是编译为 _fnEvent = new FnEvent( fnEvent ); 这可以用逆向工程的方式看看编译之后的 MSIL 以及再反编译出来的源代码来了解。
      

  2.   

    msdn:http://msdn.microsoft.com/zh-cn/library/ms173176(VS.80).aspx
    上提到了“简化语法”。我第一次看到简化语法的时候,想“这样是不是就比new一个实例更快了?”,于是就去求证了一下。20分钟后发现,原来是一样的。
      

  3.   

    msdn:http://msdn.microsoft.com/zh-cn/library/ms173176(VS.80).aspx 
      

  4.   

    我举一个委托的稍微复杂一点点的小例子,求阶乘的例子(c#3.0语法并且使用int类型)Func<int, int> factorial = null;
    factorial = n =>
     {
         if (n == 0)
             return 1;
         else
             return n * factorial(n - 1);
     };这里为factorial赋值为null,然后的赋值其实是用一个匿名函数做参数来创建Fun<int,int>类型的一个对象,这个函数使用了lamda表达式。求9的阶乘就是int result=factorial(9);
    使用关键字event可以让编译器帮我们限制事件(一种特殊的delegate)调用写法。事件实例必须声明在类型范畴(而不是方法内部),它只能使用 += 和 -= 之类的写法。
      

  5.   

    委托类型Func<T,R>在.net中是这样定义的:public delegate TResult Func<T, TResult>(T arg);
    它定义一个“一个输入参数arg的类型为T,输出类型为TResult”的delegate。由于使用泛型,那么在实际定义类似类型时直接从泛型映射为类型(将泛型的类型参数赋值为具体类型)就可以了,而不再需要逐一定义具体的类型。所以我使用 Func<int,int> 来声明 factorial 的类型。委托有 Combine 方法。例如Func<int, int> factorial = null;
    factorial = n =>
    {
        if (n == 0)
            return 1;
        else
            return n * factorial(n - 1);
    };
    factorial += n => n * 10;
    这最后一句就被编译器编译为factorial = (Func<int, int>) Delegate.Combine(factorial, n => n * 10);
    它把原来的factorial实例跟新的匿名方法(c#所支持的lamda表达式允许对于只有一行的函数省略return关键字)合并起来,然后将合并得到的新实例再赋值给factorial。实际上我们在为事件注册处理方法时看到的也就是这个Combine操作。不过这个例子运行,就会发现 factorial(9) 只是返回90,而不再是阶乘了。这是因为合并过多个delegate的最终delegate运行时实际上仍然执行了所有delegate,可是它的返回值仅仅被最后一个delegate调用方法的返回值反映出来。在我们触发事件时,如果服务要从客户程序获取一些资料,但是有多个客户程序都注册了对这个服务对象的这个事件进行处理,结果服务事件就只能得到最后一个处理程序的结果。要想手动地去执行每一个方法也不难,只要这样调用delegate:foreach (Func<int,int> f in factorial.GetInvocationList())
        Console.WriteLine(f(9));这样就可以细致地逐一调用每一个delegate。
      

  6.   

    呵呵,说了这么多,我要说的是:当你多了解一些delegate知识,很快就会发现它比一个函数或者IntPtr指针的内容要丰富得多的多了。