zoukankan      html  css  js  c++  java
  • 无法将匿名方法转换为System.Delegate

    在WinForm中,不允许非UI线程访问UI,如果非UI线程需要跨线程调用UI控件,通常的解决办法是使用Control类中的Invoke方法,传递给该方法一个委托和委托调用的参数列表(params []object args),任何委托类型都可以,通过委托来访问UI。其内部是,非UI线程把委托送到UI线程中,让UI线程去调用这个委托。

    一般一个方法的参数是委托类型,如果使用委托实例,那就还需要额外定义一个和委托签名一致的方法,比较麻烦。而我一般是使用匿名方法,因为匿名方法方便,不需要额外的声明的一个委托类型了,让代码更加简洁。但是这一次使用匿名方法却出现了错误,在编译的时候就没有被通过,我代码如下(code1):

     this.Invoke(delegate(string test) {this.Text=test;},"myCall");
    

    编译时错误如下:

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

    经过仔细思考,发现这样的写法通过编译确实是对的。首先得明白所有的委托类型都是继承System.Delegate,而Invoke方法委托类型就是Delegate,也就是说,任意的委托类型都可以作为该方法的参数。如果我们使用匿名方法,那么CLR就不知道把该匿名方法转为哪种类型的的委托,因此直接传入一个匿名函数是通不过编译的。知道了为什么错误,代码改成下面这样(code2),就能够正确的运行罗。

    Action<string> updateUI = (text) => this.Text = text;
    this.Invoke(updateUI,"myCall");
    // 或者这样,和上面一样,还是传入Action<string>委托实例
    this.Invoke(new Action<string>((text) => this.Text = text), "myCall");
    

    在使用委托类型的时候,建议最好采用系统内部定义Action和Func两种委托类型,而且这两种类型还定义了许多个泛型版本,足够满足我们平常的应用啦。

    那么在哪种情况下可以直接传入匿名方法作为参数,举个例子,在使用Linq的扩展Where方法的时候,该方法需要传入一个委托,委托的定义为Func<T,bool>,这种情况我们可以直接使用一个匿名方法,代码如下(code3):

    list.Where((s) => s.StartsWith("n"));
    

    因此可以知道,当方法的参数是具体的委托类型时,可以使用匿名方法,因为编译器知道应该把该匿名方法转为何种委托类型;而 当方法的参数为委托的基类System.Delegate时,那就需要自己实例化一个具体委托类型实例(委托类型使用.NET内部定义的,如code2),然后传入进去,这样CLR知道就是何种委托类型。

    在C#3.0中有了一个叫Lambda的表达式,和匿名方法是一样效果,但是Lambda能够使代码更加紧凑,更加优异,主要是比较容易理解表达式,可读性好,关于Lambda的用法在这里就不做介绍了。上面的code2和code3的匿名方法都是采用的Lambda表达式,是不是看起来更加简洁。

  • 相关阅读:
    3.16
    3.8
    3.7
    3.6
    3.5
    3.3
    3.2
    《机器学习十讲》学习报告一
    机器学习-集成算法
    机器学习-基于核的算法
  • 原文地址:https://www.cnblogs.com/mingjiatang/p/5982836.html
Copyright © 2011-2022 走看看