关闭顶部展开顶部

谈如何使用 Lambda 表达式做抽象代表_.Net教程

编辑Tag赚U币
教程Tag:暂无Tag,欢迎添加,赚取U币!

推荐:浅析C# 2010命名和可选参数的新特性
1.命名参数允许调用者通过提供参数的名称来为其赋值,这样参数的位置就不在重要了。可选参数允许在定义时为某些参数赋值,在调用时可以忽略这些

Lambda表达比代表定义和带外方法定义的结合更清楚,且相关的额外工作只需要满足语言定义即可。不过,它也有一些不足之处。如果某个方法的参数包含System.Delegate 这样的抽象类型,用lambda表达式介绍特殊的问题:C#编译器不能将lambda表达式转换成还未明确定义的衍生代表类型。

如果不仔细思考一下,你的代码看上去就会像是来自.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 怎样简化与老式应用程序接口(下图)的运行。

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

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

更新应用程序

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

MyTime.Background = newBrush;

MyTime.Content = label

计时器在背景线程上运行,所以你需要通过使用Dispatcher.Invoke()边界线执行调用。这两行代码是你想列入lambda表达式的代码,不是证明方法定义的逻辑理由。但是我之前就讲过lambda不会与Didpatcher.Invoke一起运行,除非是你使用了具体的代表定义才行。这之中的一部分已经在.NET框架3.5中定义了。

我们可以使用嵌入式代表定义并对它们进行分配,这些都是的该解决方案比起先前提到过的案例都要省事一些。这两行代码也要求一对参数:一个用于文本的字符串和用于背景颜色的颜色刷。这意味着你需要使用的代表定义要考虑到这两个参数并返回无效值:

Action updateTimer;

在声明变量后,你可以为代码指定需要执行的代表变量。这里你可以使用lambda表达式,因为Action是一个具体的代表定义:

updateTimer = (label, newBrush) =>

{

MyTime.Background = newBrush;

MyTime.Content = label;

};

现在,当计时器提出事件时,你已经拥有了一些需要执行的指向该代码的变量。接下来要做的就只是通过Dispatcher.Invoke()使用代表定义:


if (!MyTime.Dispatcher.CheckAccess())

{

MyTime.Dispatcher.Invoke(updateTimer,

newLabel, next);

}

else

updateTimer(newLabel, next);

这一过程十分简单,但是却要求你反复进行,因此,我们可以让步骤变得容易一点。

这里其实由一个简单的模式。事件处理器可以从背景线程中调用出来。当我们使用计时器,或者异步调用Web服务以及其他类似任务的时候,你就会看到这一行为。无论是在什么时候,我们都不清楚自己位于哪个线程之上,我们可以调用Dispatcher.CheckAccess()来决定是否可以访问任意用户界面控件。如果需要从线程边界执行调用,就必须使用Dispatcher.Invoke()。Dispatcher.Invoke()方法避免了由于使用了方法参数的参数数组而造成的若干超载问题。它使用的是一个我们想要执行的抽象代表类型。

你想要一个能检查是否需要整理编排的单一方法。如果需要,则方法会编排好调用,否则,会调用由代表指定的方法。你虚伪方法作为System.Windows.Controls.Control 类型的成员出现。这样使得你可以将代码作为控件的一部分来使用。C#3.0就为你提供了这样做的方法:扩展方法。你需要编写一些方法的不同超载,这些使得你可以通过不同的参数来使用它们:

public static class WPFExtensions:

{

public static voidInvokeIfNeeded(

this Control widget,

Action whatToDo)

{

if (!widget.Dispatcher.

CheckAccess())

widget.Dispatcher.Invoke(whatToDo);

else

whatToDo();

}

public static void

InvokeIfNeeded(

this Controlwidget, Action

whatToDo, T parm)

{

if (!widget.Dispatcher.CheckAccess())

widget.Dispatcher.Invoke(whatToDo, parm);

else

whatToDo(parm);

}

public static void

InvokeIfNeeded(this

Controlwidget, Action

whatToDo,

T1 parm1, T2 parm2)

{

if (!widget.Dispatcher.

CheckAccess())

widget.Dispatcher.

Invoke(whatToDo,

parm1, parm2);

else

whatToDo(parm1, parm2);

}

}

当然,我们也可以通过添加更多参数的方式来添加更多超载以扩展这个类。这其实是一个简单的扩展。

有一种方法让WPF设计师们疯狂:他们希望用最小化应用程序接口的面积部分来简化Dispatcher对象的使用。通过使用抽象代表和参数列表中的参数,这一对象的使用范围被扩大了。

任何带有参数的方法都可以被拿来使用。但是,这样做有一个不足之处。该应用程序接口更为抽象,它会破坏所有类型的安全性,而且这样做会损坏编译器使用类型推理的能力,从而降低工作效率。需要做的应该是添加自己的安全扩展方法的层类型,这一层类型可以在类型安全调用和更为抽象的.NET库应用程序接口之间提供一个层。

分享:浅析WinForm程序中使用控制台作为输出窗口
最初打算写一个log窗口类,使用textbox控件以及 progressbar,后来发现挺麻烦,远不及console窗口下的console.write和console.writeline方便。于是尝试直接将信息输出到控制台窗口。 1、 在winform程序中调用console窗口。这个使用Win32 API来完成。关于Allo

来源:模板无忧//所属分类:.Net教程/更新时间:2009-08-22
loading.. 评论加载中....
相关.Net教程
闂佹眹鍩勯崹閬嶆偤閺囶澁缍栭柛鈩冪⊕閳锋帗銇勯弴妤€浜惧銈忕秶閹凤拷
濠电偛顕慨顓㈠磻閹炬枼妲堥柡鍌濇硶婢ф稒淇婇懠顒夆偓婵嬫煟閵忊晛鐏查柟鍑ゆ嫹
濠电姷顣介埀顒€鍟块埀顒勵棑缁辩偛顓兼径瀣閻庣懓瀚竟鍡欐崲娑斾線鏌i姀鈺佺伈闁瑰嚖鎷�
濠电姷顣介埀顒€鍟块埀顒勵棑缁辩偛顓兼径濠勵吋闂佽鍨庨崟顓фК闂佽閰eḿ褍螞濞戙垺鍋夐柨鐕傛嫹
闂備胶枪缁绘劙骞婃惔銊ョ劦妞ゆ帒鍊哥敮鍫曞箹鐎涙ḿ鐭掔€规洘绻堥弫鎾绘晸閿燂拷
闂備胶枪缁绘劙骞婃惔銊ョ劦妞ゆ巻鍋撻柛姘儑缁﹪鏁傞崜褏鐓撻柣搴岛閺呮繈鎯屽▎鎴犵=濞撴艾锕ョ€氾拷
闂備浇銆€閸嬫挻銇勯弽銊р槈闁伙富鍣i弻娑樷攽閹邦亞鑳虹紓浣靛妽濡炶棄顕i妸鈺婃晬婵炲棙鍨电粭锟犳⒑閸濆嫬鈧骞婇幘鑸殿潟闁跨噦鎷�
闂備礁鎼崯鐗堟叏妞嬪海绀婂鑸靛姈閻擄綁鎮规潪鎷岊劅婵炲眰鍊曢湁闁挎繂妫欑粈鈧梺鍛娚戦悧鐘茬暦閹扮増鏅搁柨鐕傛嫹
婵犵妲呴崹顏堝礈濠靛棭鐔嗘俊顖氬悑鐎氱粯銇勯幘瀵哥畺閻庢熬鎷�
濠电姷顣介埀顒€鍟块埀顒勵棑缁辩偛顓奸崶銊ヮ伕濡炪倖鎸荤换鍐偓姘虫珪娣囧﹪顢涘Δ鈧晶鍙夌節椤喗瀚�
婵犵妲呴崹顏堝礈濠靛棭鐔嗘慨妞诲亾鐎规洦鍓熼、娆撳礂閻撳簶鍋撻悽鍛婄厸闁割偅绻勫瓭婵犳鍣幏锟�
婵犵妲呴崹顏堝礈濠靛棭鐔嗘慨妞诲亾闁哄苯鎳橀崺鈧い鎺嗗亾闁宠閰i獮鎴﹀箛闂堟稒顔嗛梻浣告惈鐎氭悂骞忛敓锟�
婵犵妲呴崹顏堝礈濠靛棭鐔嗘慨妞诲亾鐎规洩缍侀獮瀣攽閸偂绱�
濠电姷顣介埀顒€鍟块埀顒勵棑缁辩偛顓兼径濠勭厬闂佺懓鐡ㄧ换鍕敂鐎涙ü绻嗘い鏍殔婢у弶绻濋~顔藉
闂佽楠搁崢婊堝礈濠靛鍋嬮柟鎯版閻鈹戦悩鎻掓殭闁奸潧缍婇弻銈夋嚍閵夈儱顫嶉梺缁樼壄缂嶄礁鐣峰▎鎾存櫢闁跨噦鎷�
UB闂備礁婀辩划顖炲礉濡ゅ懐宓侀柛銉㈡櫆鐎氭岸鎮楀☉娅虫垿锝為敓锟�
闂備浇澹堟ご绋款潖婵犳碍鐒鹃悗鐢电《閸嬫捇鐛崹顔句痪濠电姭鍋撻柨鐕傛嫹
闂佽楠哥粻宥夊垂閸濆嫸鑰块柛銏㈠殰
闂備礁鎲″缁樻叏妞嬪海绀婂璺虹灱閸楁碍绻涢崱妤€顒㈤柛鐐差槹缁绘稓绱欓悩鍝勫帯闂佺ǹ楠忛幏锟�
缂傚倸鍊烽悞锕傛偡閿曞倸鍨傛繝濠傚椤╅攱銇勯幒宥囶槮缂佹彃婀遍埀顒傚仯閸婃繄绱撳棰濇晩闁跨噦鎷�
©2017 www.mb5u.com婵犵妲呴崹顏堝礈濠靛棭鐔嗘慨妞诲亾鐎殿噮鍣i幃鈺呭箵閹烘挸鐦�
闂備浇銆€閸嬫捇鏌熼婊冾暭妞ゃ儻鎷�&闂備礁鎲$敮鎺懳涢弮鍫燁棅闁跨噦鎷�