zoukankan      html  css  js  c++  java
  • 无法将 匿名方法 转换为类型“System.Delegate”,因为它不是委托类型

    http://blog.csdn.net/xiaochongchong1248/archive/2009/11/20/4841193.aspx?1271573283

    编程环境要求:VS2008/FX2.0

    众所周知,从VS2005/FX2.0起,在多线程环境下是不允许跨线程修改主线程上窗口控件的。

    例如:

    private void button1_Click(object sender, EventArgs e)
    {
        Thread t 
    = new Thread(new ThreadStart(CrossThreadCall));
        t.Start();
    }
    public void CrossThreadCall()
    {
        Text 
    = "test";
    }


    将直接导致异常:
    未处理 System.InvalidOperationException
      Message="线程间操作无效: 从不是创建控件“Form1”的线程访问它。"
      Source="System.Windows.Forms"
      StackTrace:
           在 System.Windows.Forms.Control.get_Handle()
           在 System.Windows.Forms.Control.set_WindowText(String value)
           在 System.Windows.Forms.Form.set_WindowText(String value)
           在 System.Windows.Forms.Control.set_Text(String value)
           在 System.Windows.Forms.Form.set_Text(String value)
           在 delegate_test1.Form1.CrossThreadCall() 位置 f:\app\delegate_test1\delegate_test1\Form1.cs:行号 26
           在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           在 System.Threading.ThreadHelper.ThreadStart()

    通用的解决方法是使用Control.Invoke方法来调用一个Delegate,从而安全地跨线程调用。

    例如:

    public void CrossThreadCall()
    {
        Invoke(
    new void_d(CrossThreadCall_Local));
    }
    void CrossThreadCall_Local()
    {
        Text 
    = "test";
    }
    public delegate void void_d();


    但是这样的缺点是要不得不为每个调用编写一个Invoke跳板,还要额外声明一个委托类型,实在不怎么优雅。

    于是我们想到用匿名函数来写。我的第一反应是:

    Invoke(delegate { Text = "test"; });


    可惜不行。编译压根就没通过,写着:
    无法将 匿名方法 转换为类型“System.Delegate”,因为它不是委托类型

    无语,delegate竟然不是委托类型?

    等我把Google翻了一遍后,找到了答案。

    The problem the user is seeing is that the Thread ctor accepts a specific delegate -- the ThreadStart delegate.  The C# compiler will check and make sure your anonymous method matches the signature of the ThreadStart delegate and, if so, produces the proper code under-the-covers to create the ThreadStart delegate for you.

    But Control.Invoke is typed as accepting a "Delegate".  This means it can accept any delegate-derived type.  The example above shows an anonymous method that has a void return type and takes no parameters.  It's possible to have a number of delegate-derived types that match that signature (such as MethodInvoker and ThreadStart -- just as an example).  Which specific delegate should the C# compiler use?  There's no way for it to infer the exact delegate type so the compiler complains with an error.

    也就是说,对于Thread.ctor()来说,由于接受的是一个ThreadStart委托,编译器便可以将匿名函数与ThreadStart委托类型匹配,最后能够正确编译。
    而对于Control.Invoke()来说,任何的代理类型都是可接受的,也就是说ThreadStart和MethodInvoker都是可以接受的类型。这样编译器反而不知道应该用哪个代理去匹配匿名函数了,导致了编译错误的发生。

    知道了原因,问题就很容易解决了。我们只需要加上MethodInvoker这个wrapper就能使用匿名函数了。

    Invoke(new MethodInvoker(delegate { Text = "test"; }));


    或者更简单地,用Lambda表达式来解决问题:

    Invoke(new MethodInvoker(() => Text = "test"));


    希望本文能够帮助有同样困惑的朋友。

    作者: 火地晋
    出处: http://yelaiju.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    hdu 2602 Bone Collector 01背包
    总结
    类--接口 抽象父类 多态 鸭子类型 格式化方法与析构方法 反射 异常处理 自定义异常 断言
    类--组合 继承 super关键字 面向对象的三大性
    面向对象 名称空间 类与对象
    re正则模块 垃圾回收机制
    常用模块--hashlib hmac:加密 xml xlrd xlwt:excel读|写 configparser subprocess
    常用模块-- random shutil shevle logging sys.stdin/out/err
    常用模块-- time os sys 递归 序列化

  • 原文地址:https://www.cnblogs.com/yelaiju/p/1827691.html
Copyright © 2011-2022 走看看