日期:2010-03-03  浏览次数:20419 次

如果不仔细思考一下,你的代码看上去就会像是来自.NET1.0的东西。在本文中,我将告诉告诉你为什么lambda表达式不足以被直接转换成抽象代表类型,并且教你怎样使得编译器转换你所定义的指定代表。解决方案依赖于Windows Presentation Foundation(WPF)和System.Windows.Threading.Dispatcher组件,但是严格意义上说,该问题不是一个WPF问题。文中所描述的问题出现在若干.NET框架中,包括Windows Forms,Office 应用程序接口和映射应用程序接口。你可以按照下列方法来处理同类问题。

无论我什么时候使用.NET框架中带有来自代表表格的参数的应用程序接口,我都会倾向于使用lambda表达式而不是更详细的表达式。例如,这行代码创建了一个System.Windows.Threading.Timer,在计时器失效时,该代码调用了一个TickHandler方法:

以下为引用的内容:

tick = new System.Threading.Timer((unused) => 
      

TickHandler());

如果方法的内容足够少,我就会用方法的内容替代TickHandler()方法调用。该方法大多数情况下都有效,但是当应用程序接口将System.Delegate作为参数时,这一技巧不管用。例如,我们将System.Windows.Controls.Dispatcher.Invoke()方法穿过WPF中的线程实施调用:

以下为引用的内容:

public object Invoke( 

delegate method,

params object[] args)

现在考虑一下当我们尝试用lambda表达式来执行这样的调用时,将会发生什么:

以下为引用的内容:

MyTime.Dispatcher.Invoke(() => DoSomething());

会出现隐秘错误:

以下为引用的内容:

error CS1660: Cannot convert lambda expression to
     

type 'System.Delegate' because it is not a delegate type

或许第一次看到这个错误的时候,你还不知道到底是怎么一回事。当然,这的确是一个代表类型。编译器不像人一样的灵活。System.Delegate类型是一个抽象类型,且该类型的推理工具不能推断出自变量或某些用于未知代表类型的返回值的数量和种类。要解决这一问题,我们必须创建一个具体的代表类型并为该类型指定lambda表达式。记住,代表类型要求你将方法视为数据。

我创建了一个WPF计时器程序来展示其工作原理,其中阐述了C#3.0 怎样简化与老式应用程序接口(下图)的运行。

当你做演示的时候,该示例中的应用程序运行了一个计时器,随着设定时间流逝,它的颜色会从绿色转为黄色再转为红色。这是一个很好的演示跨线程调用的方法,因为该计时器在背景线程中运行。

按照时间的改变来更新演示要求对出自计时器的事件作出响应。计时器在背景线程中运行,所以你会很轻易地犯我们在前面提到过的错误。

更新应用程序

用户界面处理的是简单代码。当计时器失效时它会生效,而且代码会更新计时器的显示。这一更新必须改变文本,或控制背景。如下所示: