Aide à la compréhension de la syntaxe C # lors de l’appel d’une nouvelle action

Je suis nouveau sur c # et ne comprends pas la syntaxe d’invocation d’une nouvelle action, ni même de ce qu’est une action. D’après ce que j’ai compris dans Port1_DataReceived, je dois créer une action car je suis dans une nouvelle marche … Quelqu’un peut-il expliquer pourquoi je dois le faire?

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; ssortingng Line = ""; int BytestoRead = Port.BytesToRead; Line = Port.ReadLine(); label1.Invoke(new Action(() => { label1.Text = Line; })); } 

Le code que j’ai du mal à comprendre est le suivant:

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

Quelqu’un peut-il décomposer ce que cela fait .. Je suis sûr que ce n’est rien de compliqué, juste que je n’ai jamais rien vu de tel auparavant. La syntaxe qui me tient vraiment debout est ()=> la nouvelle action pointe vers le code ci-dessous ou quelque chose comme ça ??

Cela utilise quelque chose appelé “expression lambda” pour créer un délégué anonyme qui correspond à la signature attendue par le constructeur Action.

Vous pouvez obtenir le même effet comme ceci:

 label1.Invoke(SetText); ... public void SetText() { label1.Text = Line; } 

ou comme ceci:

 label1.Invoke(new Action(SetText)); ... public void SetText() { label1.Text = Line; } 

ou comme ceci:

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

ou comme ceci:

 label1.Invoke(delegate() { label1.Text = Line; }); 

ou comme ceci:

 label1.Invoke(() => label1.Text = Line); 

Ce ne sont généralement que des raccourcis syntaxiques facilitant la représentation d’une action.

Notez que les expressions lambda ont souvent des parameters. Lorsqu’il n’y a qu’un seul paramètre, les parenthèses sont facultatives:

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

Lorsqu’il n’y a pas de paramètre ou plusieurs parameters, les parenthèses sont nécessaires pour rendre évident ce que vous faites. Par conséquent, le () => .

Décomposons pièce par pièce.

 label1.Invoke( 

Ceci est la méthode Control.Invoke . Voici comment cela est défini:

 public Object Invoke(Delegate method); 

Exécute le délégué spécifié sur le thread qui possède le handle de fenêtre sous-jacent du contrôle.

Cela signifie que vous lui donnez une référence à une méthode à appeler, et Control.Invoke s’assurera qu’elle soit appelée sur le thread d’interface utilisateur (ce qui évitera les exceptions de threads croisés lors de la mise à jour de l’interface utilisateur). un paramètre, ce qui signifie que vous devez lui transmettre une méthode qui ne prend aucun paramètre et n’a aucune valeur de retour. C’est là System.Action type de délégué System.Action :

 public delegate void Action(); 

En utilisant des expressions lambda, nous pouvons créer un délégué d’ Action inline. Tout d’abord, nous spécifions le type de délégué:

 label1.Invoke(new Action( 

Ensuite, nous commencerons par la syntaxe lambda. Un ensemble vide de parenthèses indiquera que la fonction lambda ne prend aucun paramètre et une “flèche” indique ensuite que nous voulons démarrer la méthode:

 label1.Invoke(new Action(() => 

Maintenant, comme la méthode lambda n’a pas de valeur de retour (mais doit exécuter une instruction), nous devons entourer le code que nous voulons exécuter sur le thread d’interface utilisateur entre accolades:

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

Fermez la parenthèse restante et vous avez la déclaration complète et terminée.

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

Généralement, lorsque vous souhaitez append quelque chose à votre GUI et que vous travaillez à partir d’un autre thread, vous devez faire quelque chose appelé Invocation .

Pour effectuer une invocation utilisez une méthode Controls Invoke ou quelque chose comme un Application Dispatcher , ces méthodes effectuent généralement une Action . Une Action est juste ce que cela ressemble, quelque chose qui doit être effectuée.

Dans votre cas, vous souhaitez append une ligne de texte à un élément résidant dans votre interface graphique. Vous devez donc créer une Action (méthode anonyme) et dans cette action, vous dites simplement “Ajouter ceci à mon contrôle “. Et ensuite, vous Invoke ceci pour éviter les problèmes de cross-threading.

()=> est juste un “raccourci” (méthode lambda) pour créer une méthode anonyme. Cela signifie que vous ne pouvez pas appeler cela de n’importe où, à l’exception du contexte dans lequel vous avez créé la méthode anonyme.

Vous pouvez également Invoke une méthode “globale”, il n’est pas nécessaire que ce soit une méthode anonyme.

Une action est un type de délégué, autrement dit, elle encapsule une fonction. Spécifiquement, une action encapsule une fonction qui retourne void, alors qu’un Func encapsule par exemple une fonction avec une valeur de retour. Celles-ci ressemblent beaucoup à des pointeurs de fonction en C ++ – essentiellement une référence à une fonction, c’est-à-dire un moyen d’encapsuler un comportement.

La méthode .Invoke () prend le délégué Action et exécute la fonction vers laquelle il pointe. Dans ce cas, la fonction pointée est l’expression lambda:

 () => { label1.Text = Line } 

Les parenthèses initiales indiquent les parameters passés à la fonction. Dans ce cas, il n’y a pas de paramètre, les parenthèses sont vides. Par exemple, si vous voulez transmettre deux chaînes, vous feriez:

 var action = new Action( (x, y) => { // use x and y } 

Tout ce qui suit l’expression ‘=>’ est essentiellement le corps de la fonction. Vous avez access aux variables spécifiées entre parenthèses à l’intérieur de la scope de ce corps.

Globalement, il s’agit d’un moyen rapide de créer une fonction anonyme à la volée qui est essentiellement équivalente à ce qui suit:

 public void SetLine() { label1.Text = Line; } 

En tant que tel, vous pouvez également créer cet object Action en faisant:

 var action = new Action(SetLine) 

où vous passez le nom de la méthode à encapsuler au lieu de passer à un lambda. Ce qui est transmis est appelé «groupe de méthodes».

Cela génère une méthode anonyme (un lambda , précisément) et la transmet à la méthode invoke. Les Lambda sont un excellent moyen d’avoir du code dont vous n’avez besoin qu’une seule fois. Vous n’avez donc pas besoin de nombreuses méthodes d’aide qui ne font qu’une seule chose.

Cela garantit que le texte de l’étiquette est exécuté dans le fil de l’interface utilisateur. L’événement Port1_DataReceived s’exécutera probablement dans un thread en arrière-plan et la valeur de texte de l’étiquette ne doit pas être définie à partir des threads en arrière-plan. Cela empêche que cela se produise.

Je ne sais pas ce que le label1 est, mais le pourrait être lu comme:

label1 est une action, qui reçoit une autre action en paramètre. Il fait quelque chose et quand il appelle une action reçue en argument.

Maintenant, j’ai lu cela et je pourrais être un problème – label1 ne peut pas être une action. Comme c’est juste un contrôle qui définit ici: label1.Text = Line;

Vous avez une erreur dans votre application;

MODIFIER

Désolé, viens de lire ça:

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

Exécute le délégué spécifié sur le thread qui possède le handle de fenêtre sous-jacent du contrôle.

Le code est correct.

Action est un délégué. Label1.Invoke () est utilisé pour exécuter le code label1.Text = ligne pour éviter les opérations de cross-thread. le gestionnaire d’événements pour l’événement DataReceived s’exécute sur un autre thread que le thread d’interface utilisateur. label1.Invoke () exécutera le code dans le thread de l’interface utilisateur.