在调用新动作时帮助理解c#语法
本文关键字:语法 助理 帮助 调用 新动作 | 更新日期: 2023-09-27 18:01:33
我是c#新手,不了解调用新操作的语法,甚至不了解操作是什么。从我对Port1_DataReceived的理解来看,我必须创建一个动作,因为我处于一个新的阶段……谁能详细说明我为什么要这么做?
public Form1()
{
InitializeComponent();
SerialPort Port1 = new SerialPort("COM11", 57600, Parity.None, 8, StopBits.One);
Port1.DataReceived += new SerialDataReceivedEventHandler(Port1_DataReceived);
Port1.Open();
}
private void Port1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort Port = (SerialPort)sender;
string Line = "";
int BytestoRead = Port.BytesToRead;
Line = Port.ReadLine();
label1.Invoke(new Action(() =>
{
label1.Text = Line;
}));
}
我真正难以理解的代码片段是:
label1.Invoke(new Action(() =>
{
label1.Text = Line;
}));
谁能解释一下这是怎么回事?我相信这并不复杂,只是我以前从未见过这样的事情。真正让我感到困扰的语法是()=>
,新动作指向下面的代码或其他东西??
这使用了所谓的"lambda表达式"来创建一个匿名委托,该委托与Action构造函数所期望的签名相匹配。
你可以像这样达到同样的效果:
label1.Invoke(SetText);
...
public void SetText() { label1.Text = Line; }
或者像这样:
label1.Invoke(new Action(SetText));
...
public void SetText() { label1.Text = Line; }
或者像这样:
label1.Invoke(new Action(delegate() { label1.Text = Line; }));
或者像这样:
label1.Invoke(delegate() { label1.Text = Line; });
或者像这样:
label1.Invoke(() => label1.Text = Line);
这些大多只是语法上的快捷键,以便更容易地表示一个动作。
注意lambda表达式通常有参数。当只有一个参数时,括号是可选的:
list.ToDictionary(i => i.Key);
当没有参数或有多个参数时,括号是必要的,以使您正在做的事情很明显。因此,() =>
。
让我们一块一块地分解它。
label1.Invoke(
这是Control.Invoke
方法。下面是它的定义:
public Object Invoke(Delegate method);
在拥有控件的底层窗口句柄的线程上执行指定的委托。
这意味着你给它一个要调用的方法的引用,并且Control.Invoke
将确保它在UI线程上被调用(这将在更新UI时防止跨线程异常)。它接受默认的Delegate
作为参数,这意味着您需要向它传递一个不接受参数且没有返回值的方法。这就是System.Action
委托类型的由来:
public delegate void Action();
使用lambda表达式,我们可以内联创建Action
委托。首先,我们指定委托类型:
label1.Invoke(new Action(
然后,我们将开始lambda语法。一组空括号表示lambda函数不接受参数,后面的"箭头"表示我们想要启动该方法:
label1.Invoke(new Action(() =>
现在,因为lambda方法没有返回值(但必须执行一条语句),我们需要用花括号将我们想要在UI线程上执行的代码括起来:
label1.Invoke(new Action(() =>
{
label1.Text = Line;
}
关闭剩下的括号,完整的语句就完成了。
label1.Invoke(new Action(() =>
{
label1.Text = Line;
}));
一般来说,当你想要添加一些东西到你的GUI
,你正在从另一个线程工作,你需要做一些叫做Invocation
。
要创建invocation
,您可以使用控件Invoke
方法或Application Dispatcher
之类的方法,这些方法通常使用Action
。Action
顾名思义,就是要执行的任务。
在你的情况下,你正在做的是,你想要添加一行文本的元素,生活在你的GUI,所以你需要做的是创建一个Action
(匿名方法),在这个动作中,你只是说"添加到我的控制"。然后你Invoke
这个,以避免交叉线程问题。
()=>
只是一个创建方法的"快捷方式"(lambda方式),即匿名。这意味着除了创建匿名方法的上下文中,你不能从任何地方调用它。
你也可以Invoke
一个"全局"方法,它不一定是一个匿名方法。
Action是一个委托类型,换句话说,它封装了一个函数。具体来说,Action封装了一个返回void的函数,而Func封装了一个返回值的函数。它们很像c++中的函数指针——本质上是对函数的引用,即封装行为的一种方式。
. invoke()方法接受Action委托并运行它所指向的函数。在本例中,它指向的函数是lambda表达式:
() => { label1.Text = Line }
初始圆括号表示传递给函数的任何参数。在本例中,没有参数,因此括号为空。例如,如果你想传入两个字符串,你可以这样做:
var action = new Action<string, string>( (x, y) => { // use x and y }
'=>'表达式后面的内容本质上是函数体。您可以访问该主体范围内圆括号中指定的变量。
总的来说,这是一种快速创建匿名函数的方法,本质上相当于以下内容:
public void SetLine()
{
label1.Text = Line;
}
也可以这样创建Action对象:
var action = new Action(SetLine)
,其中传入要封装的方法的名称,而不是传入lambda。传递进来的东西被称为"方法组"。
Action是一个委托。label1. invoke()用于执行代码label1。Text = line以避免交叉线程操作。DataReceived事件的事件处理程序在UI线程之外的另一个线程上执行。label1.Invoke()将在UI线程中执行代码。
这将生成一个匿名方法(确切地说是一个lambda)并将其传递给invoke方法。lambda是一种很棒的方法,可以让代码只需要使用一次,这样就不需要大量的帮助方法只做一件事。
这确保标签的文本在UI线程中运行。Port1_DataReceived事件可能会在后台线程中运行,而Label的文本值不应该从后台线程中设置。这可以防止这种情况发生。
我不知道label1是什么,但是可以读作:
label1是一个Action,它接收另一个Action作为参数。当它调用参数中接收到的动作时,它会做一些事情。
现在,我已经读了,我可能是一个问题- label1不能是一个动作。因为它只是一个设置在这里的控件:label1。Text = Line;
你的应用程序出现错误;
编辑
对不起,读一下:
http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx在拥有控件的底层窗口句柄的线程上执行指定的委托。
代码正确