在调用新动作时帮助理解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;
          }));
谁能解释一下这是怎么回事?我相信这并不复杂,只是我以前从未见过这样的事情。真正让我感到困扰的语法是()=>,新动作指向下面的代码或其他东西??

在调用新动作时帮助理解c#语法

这使用了所谓的"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之类的方法,这些方法通常使用ActionAction顾名思义,就是要执行的任务。

在你的情况下,你正在做的是,你想要添加一行文本的元素,生活在你的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

在拥有控件的底层窗口句柄的线程上执行指定的委托。

代码正确