在调用新Action时帮助理解C#语法

Ric*_*ard 5 c# action invoke

我是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;
      }));
}
Run Code Online (Sandbox Code Playgroud)

我真正理解的代码片段是:

label1.Invoke(new Action(() =>
         {
              label1.Text = Line;
          }));
Run Code Online (Sandbox Code Playgroud)

有人可以分解这是做什么的......我相信这并不复杂,只是因为我以前从未见过这样的事情.真正阻碍我的语法是()=>新动作是指向下面的代码还是什么?

Str*_*ior 11

这使用称为"lambda表达式"的东西来创建一个与Action构造函数所期望的签名匹配的匿名委托.

你可以达到同样的效果:

label1.Invoke(SetText);
...
public void SetText() { label1.Text = Line; }
Run Code Online (Sandbox Code Playgroud)

或者像这样:

label1.Invoke(new Action(SetText));
...
public void SetText() { label1.Text = Line; }
Run Code Online (Sandbox Code Playgroud)

或者像这样:

label1.Invoke(new Action(delegate() { label1.Text = Line; }));
Run Code Online (Sandbox Code Playgroud)

或者像这样:

label1.Invoke(delegate() { label1.Text = Line; });
Run Code Online (Sandbox Code Playgroud)

或者像这样:

label1.Invoke(() => label1.Text = Line);
Run Code Online (Sandbox Code Playgroud)

这些大多只是语法快捷方式,以便更容易表示操作.

请注意,lambda表达式通常具有参数.当只有一个参数时,括号是可选的:

list.ToDictionary(i => i.Key);
Run Code Online (Sandbox Code Playgroud)

当没有参数或多个参数时,括号是必要的,以使你明白你正在做什么.因此,() =>.


Ada*_*ras 6

让我们一块一块地分解它.

label1.Invoke(
Run Code Online (Sandbox Code Playgroud)

这是Control.Invoke方法.以下是它的定义:

public Object Invoke(Delegate method);
Run Code Online (Sandbox Code Playgroud)

在拥有控件的基础窗口句柄的线程上执行指定的委托.

这意味着你给它一个要调用的方法的引用,并Control.Invoke确保它在UI线程上被调用(这将在更新UI时防止交叉线程异常.)它将默认值Delegate作为参数,意味着你需要传递一个不带参数且没有返回值的方法.这是System.Action委托类型的来源:

public delegate void Action();
Run Code Online (Sandbox Code Playgroud)

使用lambda表达式,我们可以创建一个Action内联委托.首先,我们指定委托类型:

label1.Invoke(new Action(
Run Code Online (Sandbox Code Playgroud)

然后,我们将开始lambda语法.一组空括号将表示lambda函数不带参数,之后的"箭头"表示我们要启动方法:

label1.Invoke(new Action(() =>
Run Code Online (Sandbox Code Playgroud)

现在,因为lambda方法没有返回值(但必须执行一个语句),我们需要在大括号中围绕我们想要在UI线程上执行的代码:

label1.Invoke(new Action(() =>
{
    label1.Text = Line;
}
Run Code Online (Sandbox Code Playgroud)

关闭剩余的括号,你就有了完整的语句.

label1.Invoke(new Action(() =>
{
    label1.Text = Line;
}));
Run Code Online (Sandbox Code Playgroud)