Помогите понять синтаксис C # при запуске нового действия - PullRequest
5 голосов
/ 07 июля 2011

Я новичок в 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;
          }));

Может кто-нибудь сломать то, что он делает ... Я уверен, что ничего сложного,что я никогда не видел ничего подобного раньше.Синтаксис, который действительно удерживает меня: ()=> новое действие указывает на код ниже или что-то в этом роде ??

Ответы [ 8 ]

9 голосов
/ 07 июля 2011

При этом используется нечто, известное как «лямбда-выражение», для создания анонимного делегата, который соответствует сигнатуре, ожидаемой конструктором 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);

В основном это просто синтаксические ярлыки, облегчающие представление действия.

Обратите внимание, что лямбда-выражения часто имеют параметры.Когда есть только один параметр, круглые скобки являются необязательными:

list.ToDictionary(i => i.Key);

Когда нет параметров или нескольких параметров, скобки необходимы, чтобы было понятно, что вы делаете.Следовательно, () =>.

6 голосов
/ 07 июля 2011

Давайте разберем его по частям.

label1.Invoke(

Это метод Control.Invoke. Вот как это определяется:

public Object Invoke(Delegate method);

Выполняет указанный делегат в потоке, которому принадлежит основной дескриптор окна элемента управления.

Это означает, что вы даете ему ссылку на метод для вызова, и Control.Invoke будет гарантировать, что он будет вызван в потоке пользовательского интерфейса (что предотвратит перекрестные исключения при обновлении пользовательского интерфейса). по умолчанию Delegate как параметр, что означает, что вам нужно передать ему метод, который не принимает параметров и не имеет возвращаемого значения. Вот где приходит тип делегата System.Action:

public delegate void Action();

Используя лямбда-выражения, мы можем создать линейный делегат Action. Сначала мы указываем тип делегата:

label1.Invoke(new Action(

Затем мы начнем лямбда-синтаксис. Пустой набор скобок будет означать, что лямбда-функция не принимает параметров, а «стрелка» впоследствии показывает, что мы хотим запустить метод:

label1.Invoke(new Action(() =>

Теперь, поскольку лямбда-метод не имеет возвращаемого значения (но должен выполнять инструкцию), нам нужно заключить код, который мы хотим выполнить в потоке пользовательского интерфейса, в фигурные скобки:

label1.Invoke(new Action(() =>
{
    label1.Text = Line;
}

Закройте оставшиеся круглые скобки, и у вас будет полное законченное утверждение.

label1.Invoke(new Action(() =>
{
    label1.Text = Line;
}));
1 голос
/ 07 июля 2011

Действие - это тип делегата, другими словами, оно инкапсулирует функцию. В частности, Action инкапсулирует функцию, которая возвращает void, тогда как, например, Func инкапсулирует функцию с возвращаемым значением. Они очень похожи на указатели на функции в C ++ - по сути, это ссылка на функцию, то есть способ инкапсулировать поведение.

Метод .Invoke () принимает делегат Action и запускает функцию, на которую он указывает. В этом случае функция, на которую она указывает, является лямбда-выражением:

() => { 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) 

где вы передаете имя метода для инкапсуляции вместо передачи в лямбду. То, что передается, известно как «Группа методов».

1 голос
/ 07 июля 2011

Обычно, когда вы хотите что-то добавить к вам GUI и вы работаете из другого потока, вам нужно сделать что-то под названием Invocation.

Чтобы создать invocation, вы используете либо Controls Invoke метод или что-то вроде Application Dispatcher, эти методы обычно принимают Action.Action - это как звучит, то, что должно быть выполнено.

В вашем случае вы хотите добавить строку текста к элементу, который живет в вашем GUI,так что вам нужно создать Action (метод анонимной), и в этом действии вы просто скажете «Добавить это в мой элемент управления».И затем вы Invoke это, чтобы избежать проблем с многопоточностью.

()=> это просто «ярлык» (лямбда-способ) для создания метода, который является анонимным.Это означает, что вы не можете вызывать это откуда угодно, кроме контекста, в котором вы создали анонимный метод.

Вы также можете Invoke «глобальный» метод, он не обязательно должен быть анонимным методом.

0 голосов
/ 07 июля 2011

Действие является делегатом. Label1.Invoke () используется для выполнения кода label1.Text = line во избежание операции Cross Threading. обработчик события DataReceived выполняется в другом потоке, отличном от потока пользовательского интерфейса. label1.Invoke () выполнит код в потоке пользовательского интерфейса.

0 голосов
/ 07 июля 2011

Я не знаю, что такое label1, но это можно прочитать как:

label1 - это Действие, которое получает другое действие в качестве параметра. Он что-то делает и когда вызывает действие, полученное в аргументе.

Теперь, я прочитал это, и у меня может быть проблема - label1 не может быть Action. Так как это просто элемент управления, который установлен здесь: label1.Text = Line;

В вашем приложении есть ошибка;

EDIT

Извините, просто прочитайте это:

http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

Выполняет указанный делегат в потоке, которому принадлежит основной дескриптор окна элемента управления.

Код правильный.

0 голосов
/ 07 июля 2011

Это гарантирует, что текст метки выполняется в потоке пользовательского интерфейса. Событие Port1_DataReceived, скорее всего, будет выполняться в фоновом потоке, и текстовое значение метки не следует устанавливать из фоновых потоков. Это предотвращает это.

0 голосов
/ 07 июля 2011

Это генерирует анонимный метод (точнее лямбда ) и передает его методу invoke.Лямбды - отличный способ получить код, который вам нужен только один раз, поэтому вам не нужно много вспомогательных методов, выполняющих только одну вещь.

...