无法将 匿名方法 转换为类型“System.Delegate”,因为它不是委托类型

看了些博客,感觉还是没说清楚,下面说说自己的理解。

在多线程环境下是不允许跨线程修改主线程上窗口控件的,所以在子线程中对控件进行修改应该使用控件的Invoke方法,Invoke方法的定义是在拥有此控件的基础窗口句柄的线程上执行指定的委托。也就是说它会自动寻找创建该控件的线程(一般是主线程),然后在该线程上执行委托里的方法,这就避免了多线程同时操作同一控件,使其状态不确定。窗体本身也具有这个方法,所以如果怕麻烦的话,可以统一用this.Invoke。

言归正传,先贴上一个正确的代码:

        delegate void ShowMessageDelegate(string mes);
        private void show(string mes)
        {
            richTextBox1.AppendText(mes);
        }
        internal void ShowMessage(string message)
        {
            ShowMessageDelegate deg = show;
            richTextBox1.Invoke(deg, message);
        }
使用Lambda表达式简化代码:
            richTextBox1.Invoke(new Action(() =>
                {
                    richTextBox1.AppendText(“aaa”);
                }));

可以看出原始代码确实太过冗余,1、声明委托类型,2、创建与该委托类型对应的方法,3、用声明的委托类型创建委托实例并赋值为自己创建的方法,4、将委托实例作为Invoke方法的参数执行。

可为什么还要加个new Action,这么多的括号也称不上简洁呀。Lambda表达式可以创建匿名方法,匿名方法可以创建委托实例,而需要的也正好是Delegate,为什么编译会报错:无法将 匿名方法 转换为类型“System.Delegate”,因为它不是委托类型。我们把代码换成:

            richTextBox1.Invoke(delegate()
                {
                    richTextBox1.AppendText(“aaa”);
                });

还是不行,说明问题不是Lambda表达式,而是匿名方法。

其实原因是Lambda表达式创建了匿名方法,匿名方法创建了委托实例,可这个实例没有委托类型,它可以看做某种委托类型的构造函数的参数,也就是说Lambda表达式取代了原始代码的2、3步,第1步没有做,那就有人问了,为什么其他方法可以这样用呢?比如开始新线程,下面是MSDN上关于匿名函数的示例代码:


void StartThread()
{
    System.Threading.Thread t1 = new System.Threading.Thread
      (delegate()
            {
                System.Console.Write("Hello, ");
                System.Console.WriteLine("World!");
            });
    t1.Start();
}

这个可以自己在VS中查看thread类的定义:

可以看到start参数是指定类型的委托,方法调用时,就把匿名函数自动转换为对应的委托类。还想深究如何转换的话可以参考C++中类的自动转换。

最后问题的解决办法就是使用内置委托,常用的就是Action,Func了,也看到别人用MethodInvoker,都是可以的。

猜你喜欢

转载自blog.csdn.net/chrisxiaoniu/article/details/80941538