+1 für die seltene Kombination, neu im Codieren zu sein und eine gute Frage zu stellen: Sie verstehen, was Sie tun möchten, und erklären es gut. Sie kennen den Begriff einfach nicht, sodass Sie ihn nicht selbst finden können.
Tim S.
10
Der Begriff, den Sie suchen, ist ein Delegierter .
Lasse V. Karlsen
stackoverflow.com/questions/6187944/… check this out, ich denke, es gibt genug Erklärungen, die du brauchst. Asp funktioniert in dieser Angelegenheit fast wie Winforms.
Der Vollständigkeit halber (in Bezug auf die verschiedenen Kommentare) ...
Wie Erik sagte, können Sie mehrere Codezeilen ausführen:
varButtonClicked=newAction(()=>{MessageBox.Show("hi");MessageBox.Show("something else");// something more useful than another popup ;)});
Wie Tim sagte, könnten Sie das ActionSchlüsselwort weglassen
ActionButtonClicked=()=>MessageBox.Show("hi");ActionButtonClicked=()=>{// multiple lines of code};
Um auf KRyans Kommentar zu den leeren Klammern einzugehen, der die Liste der Parameter darstellt, die Sie an die Aktion senden möchten (in diesem Fall keine) .
Wenn Sie beispielsweise die anzuzeigende Nachricht angeben möchten, können Sie "message" als Parameter hinzufügen (beachten Sie, dass ich geändert Actionhabe , um einen einzelnen Zeichenfolgenparameter anzugeben) :Action<string>
Action ButtonClicked = () => MessageBox.Show("hi");ist gleichwertig und IMO schöner (fügen Sie parens hinzu, wenn Sie bevorzugen)
Tim S.
1
Es ist auch möglich, dass die Aktion in mehr als eine einzelne Codezeile aufgelöst wird.
Erik Philips
2
@ CSharpie Ich bin mir nicht sicher, ob diese Annahme für das OP hilfreich ist.
Erik Philips
2
@CSharpie Warum konnte das OP dies nicht verwenden WinForms?
Vivat Fische
2
@ CSharpie Ich verstehe, was du sagst. Wenn er dies tatsächlich an ein Button.ClickEreignis anfügt und es nicht in einer Variablen speichert, die er zufällig benannt hat ButtonClicked.
Vivat Fische
51
In Ihrem Fall möchten Sie a verwenden delegate.
Mal sehen, wie ein Delegierter arbeitet und wie wir zu einer einfacheren Form gelangen können, indem wir sein Konzept verstehen:
// Create a normal functionvoidOnButtonClick(){MessageBox.Show("Hello World!");}// Now we create a delegate called ButtonClickdelegatevoidButtonClick();
Sie sehen, der Delegat hat die Form einer normalen Funktion, jedoch ohne Argumente (er kann wie jede andere Methode eine beliebige Anzahl von Argumenten annehmen, der Einfachheit halber jedoch nicht).
Verwenden wir jetzt das, was wir haben. Wir definieren den Delegaten genauso wie jede andere Variable:
Wir haben im Grunde eine neue Variable namens ButtonClicked erstellt, die einen ButtonClick-Typ (der ein Delegat ist) hat und bei Verwendung die Methode in der OnButtonClick () -Methode ausführt.
Um es zu benutzen, rufen wir einfach an:ButtonClicked();
Der ganze Code wäre also:
delegatevoidButtonClick();voidOnButtonClick(){MessageBox.Show("Hello World!");}voidFoo(){ButtonClickButtonClicked=newButtonClick(OnButtonClick);ButtonClicked();// Execute the function.}
Von hier aus können wir zu Lambda-Ausdrücken wechseln und sehen, wie sie in Ihrer Situation nützlich sein können:
Es gibt viele Delegierte, die bereits von .NET-Bibliotheken definiert wurden, einige davon wie Action, die keine Parameter akzeptieren und keinen Wert zurückgeben. Es ist definiert als public delegate void Action();
Sie können es jederzeit für Ihre Anforderungen verwenden, anstatt jedes Mal einen neuen Delegaten zu definieren. Im vorherigen Kontext hätten Sie zum Beispiel gerade schreiben können
das hätte das gleiche getan.
Nachdem Sie nun verschiedene Möglichkeiten zur Verwendung von Delegaten gesehen haben, verwenden wir unseren ersten Lambda-Ausdruck. Lambda-Ausdrücke sind anonyme Funktionen. Es handelt sich also um normale Funktionen, jedoch ohne Namen. Sie haben folgende Formen:
x =>DoSomethingWithX(x);(x)=>DoSomethingWithX(x);(x,y)=>DoSometingWithXY(x,y);()=>Console.WriteLine("I do not have parameters!");
In unserem Fall haben wir keine Parameter, daher verwenden wir den letzten Ausdruck. Wir können dies genauso wie die OnButtonClick-Funktion verwenden, aber wir haben den Vorteil, dass wir keine benannte Funktion haben. Wir können stattdessen so etwas tun:
dann einfach anrufen ButtonClicked();Natürlich können Sie auch mehrere Codezeilen haben, aber ich möchte Sie nicht mehr verwirren. Es würde allerdings so aussehen:
Sie können auch herumspielen, zum Beispiel eine Funktion wie die folgende ausführen:
newAction(()=>MessageBox.Show("Hello World!"))();
Entschuldigung für den langen Beitrag, hoffe es war nicht zu verwirrend :)
EDIT: Ich habe vergessen zu erwähnen, dass eine alternative Form, die, obwohl nicht oft verwendet, Lambda-Ausdrücke leichter verständlich machen könnte:
newAction(delegate(){Console.WriteLine("I am parameterless");})();
Verwenden von Generika:
// Defines a delegate that has one parameter of type string. You could pass as many parameters as you want.newAction<string>(delegate(string x){Console.WriteLine(x);})("I am a string parameter!");
Im Gegenzug könnten Sie Lambda-Ausdrücke verwenden, aber Sie müssen den Typ des Parameters nicht definieren (aber in einigen Fällen auch), zum Beispiel könnte der obige Code einfach wie folgt geschrieben werden:
newAction<string>(x =>{Console.WriteLine(x);})("I am a string parameter!");
oder:
newAction<string>(x =>Console.WriteLine(x))("I am a string parameter!");
EDIT2: Action<string>ist eine Darstellung von public void delegate Action(string obj); Action<string,string>ist eine Darstellung von public void delegate Action(string obj, string obj2);
Im Allgemeinen Action<T>ist eine Darstellung vonpublic void delegate Action<T>(T obj);
EDIT3: Ich weiß, dass der Beitrag schon eine Weile hier ist, aber ich finde das wirklich cool, um nicht zu erwähnen: Sie können dies tun, was hauptsächlich mit Ihrer Frage zusammenhängt:
Die LazyKlasse wurde speziell entwickelt, um einen Wert darzustellen, der erst berechnet wird, wenn Sie danach fragen. Sie erstellen es, indem Sie eine Methode bereitstellen, die definiert, wie es erstellt werden soll. Diese Methode wird jedoch nur einmal ausgeführt (selbst wenn mehrere Threads den Wert anfordern) und einfach den bereits erstellten Wert für zusätzliche Anforderungen zurückgeben:
var foo =newLazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));var result = foo.Value;
Denken Sie daran, dass Lazydies für Werte verwendet werden sollte, die viel Rechenleistung erfordern, und dass Sie sie nicht für die Interaktion verwenden sollten (da die Semantik .Valuelautet, dass ein Wert zurückgegeben wird, der einer Eigenschaft ähnelt, keine (interaktive) Aktion). Für solche Aktionen sollte stattdessen ein Delegat verwendet werden.
Abel
1
@Abel Nein, es ist nicht für Werte gedacht , die viel Rechenleistung erfordern, sondern für Werte, deren Initialisierung Sie verschieben möchten, bis sie angefordert werden, ohne diesen Wert mehr als einmal zu initialisieren. Hier ist der Wert von Valuewird verwendet; Es ist das DialogResultempfangene vom Anzeigen des Meldungsfelds. Der Hauptunterschied zwischen dieser Lösung und der Verwendung eines Delegaten besteht darin, ob der Wert bei jeder Anforderung neu berechnet werden soll oder nicht. Meine Interpretation der Anforderungen war, dass dies konzeptionell einen Wert initialisiert und keine zu wiederholende Operation .
Servy
Lazykann leicht falsch verwendet werden. Es hat Overhead von sich selbst, wenn es "nur" verwendet wird, um eine kleine Aufgabe aufzuschieben, wird mehr Overhead verursacht, als es gewinnt. Das Anzeigen von Nachrichtenfeldern aus einer Eigenschaft ist im Allgemeinen (imo) eine schlechte Praxis, unabhängig davon Lazy. Btw, von MSDN, ich zitiere: „lazy Initialisierung Mit der Schaffung einer großen oder ressourcenintensive Aufgabe verschieben“ . Sie können dem nicht zustimmen, aber dafür wurde es ursprünglich entwickelt.
Abel
1
@Abel Der Leistungsaufwand Lazyin einem solchen Kontext ist sicherlich vernachlässigbar. Es wird blass im Vergleich zu der Zeit, die darauf gewartet wird, dass ein Mensch auf ein Meldungsfeld klickt. Es kommt hauptsächlich auf die tatsächlichen Anforderungen der zugrunde liegenden Anwendung an. Die Unbestimmtheit der Frage macht eine objektiv korrekte Antwort unmöglich. Dies ist eine Interpretation der Frage. Was die Arbeit an einem Immobilienmakler angeht, der schlecht ist; anscheinend bist du grundsätzlich gegen das gesamte design von Lazy. Sie sind zu dieser Meinung willkommen.
Servy
Entschuldigung, Sie müssen mich missverstanden haben. Sicherlich ist MessageBox der Overhead vernachlässigbar (ich würde die Benutzeroberfläche in einer Eigenschaft einfach nicht verwenden). Ich meinte im Allgemeinen kleine Aufgaben (wie das Verschieben 2 + 3 * 4 / i), bei denen der Aufwand für die Erstellung des Abschlusses größer ist als die Berechnung selbst. Und ich denke, ich bin voll und ganz davon überzeugt Lazy, dass wir es häufig in F # verwenden (etwas weniger in C #) und wir haben auf die harte Weise gelernt, dass man vorsichtig damit sein muss, insb. in Bezug auf die Leistung.
Abel
4
Wie ich Ihre Frage lese, steht dies im Zusammenhang mit GUI-Steuerelementen?
Dieser Ereignishandler kann auf verschiedene Arten behandelt werden. Das obige Beispiel verwendet eine anonyme Funktion, aber Sie können auch Folgendes tun:
Sie können einer Variablen C # -Code zuweisen, ihn zur Laufzeit kompilieren und den Code ausführen:
Schreiben Sie Ihren Code:
// Assign C# code to the code variable.string code =@"
using System;
namespace First
{
public class Program
{
public static void Main()
{
"+"Console.WriteLine(\"Hello, world!\");"+@"
}
}
}
";
Erstellen Sie den Provider und die Parameter des Compilers:
Antworten:
Sie könnten es einem solchen zuordnen
Action
:Dann nenne es:
Der Vollständigkeit halber (in Bezug auf die verschiedenen Kommentare) ...
Wie Erik sagte, können Sie mehrere Codezeilen ausführen:
Wie Tim sagte, könnten Sie das
Action
Schlüsselwort weglassenUm auf KRyans Kommentar zu den leeren Klammern einzugehen, der die Liste der Parameter darstellt, die Sie an die Aktion senden möchten (in diesem Fall keine) .
Wenn Sie beispielsweise die anzuzeigende Nachricht angeben möchten, können Sie "message" als Parameter hinzufügen (beachten Sie, dass ich geändert
Action
habe , um einen einzelnen Zeichenfolgenparameter anzugeben) :Action<string>
quelle
Action ButtonClicked = () => MessageBox.Show("hi");
ist gleichwertig und IMO schöner (fügen Sie parens hinzu, wenn Sie bevorzugen)WinForms
?Button.Click
Ereignis anfügt und es nicht in einer Variablen speichert, die er zufällig benannt hatButtonClicked
.In Ihrem Fall möchten Sie a verwenden
delegate
.Mal sehen, wie ein Delegierter arbeitet und wie wir zu einer einfacheren Form gelangen können, indem wir sein Konzept verstehen:
Sie sehen, der Delegat hat die Form einer normalen Funktion, jedoch ohne Argumente (er kann wie jede andere Methode eine beliebige Anzahl von Argumenten annehmen, der Einfachheit halber jedoch nicht).
Verwenden wir jetzt das, was wir haben. Wir definieren den Delegaten genauso wie jede andere Variable:
Wir haben im Grunde eine neue Variable namens ButtonClicked erstellt, die einen ButtonClick-Typ (der ein Delegat ist) hat und bei Verwendung die Methode in der OnButtonClick () -Methode ausführt.
Um es zu benutzen, rufen wir einfach an:
ButtonClicked();
Der ganze Code wäre also:
Von hier aus können wir zu Lambda-Ausdrücken wechseln und sehen, wie sie in Ihrer Situation nützlich sein können:
Es gibt viele Delegierte, die bereits von .NET-Bibliotheken definiert wurden, einige davon wie Action, die keine Parameter akzeptieren und keinen Wert zurückgeben. Es ist definiert als
public delegate void Action();
Sie können es jederzeit für Ihre Anforderungen verwenden, anstatt jedes Mal einen neuen Delegaten zu definieren. Im vorherigen Kontext hätten Sie zum Beispiel gerade schreiben können
das hätte das gleiche getan.
Nachdem Sie nun verschiedene Möglichkeiten zur Verwendung von Delegaten gesehen haben, verwenden wir unseren ersten Lambda-Ausdruck. Lambda-Ausdrücke sind anonyme Funktionen. Es handelt sich also um normale Funktionen, jedoch ohne Namen. Sie haben folgende Formen:
In unserem Fall haben wir keine Parameter, daher verwenden wir den letzten Ausdruck. Wir können dies genauso wie die OnButtonClick-Funktion verwenden, aber wir haben den Vorteil, dass wir keine benannte Funktion haben. Wir können stattdessen so etwas tun:
oder noch einfacher,
dann einfach anrufen
ButtonClicked();
Natürlich können Sie auch mehrere Codezeilen haben, aber ich möchte Sie nicht mehr verwirren. Es würde allerdings so aussehen:Sie können auch herumspielen, zum Beispiel eine Funktion wie die folgende ausführen:
Entschuldigung für den langen Beitrag, hoffe es war nicht zu verwirrend :)
EDIT: Ich habe vergessen zu erwähnen, dass eine alternative Form, die, obwohl nicht oft verwendet, Lambda-Ausdrücke leichter verständlich machen könnte:
Verwenden von Generika:
Im Gegenzug könnten Sie Lambda-Ausdrücke verwenden, aber Sie müssen den Typ des Parameters nicht definieren (aber in einigen Fällen auch), zum Beispiel könnte der obige Code einfach wie folgt geschrieben werden:
oder:
EDIT2:
Action<string>
ist eine Darstellung vonpublic void delegate Action(string obj);
Action<string,string>
ist eine Darstellung vonpublic void delegate Action(string obj, string obj2);
Im Allgemeinen
Action<T>
ist eine Darstellung vonpublic void delegate Action<T>(T obj);
EDIT3: Ich weiß, dass der Beitrag schon eine Weile hier ist, aber ich finde das wirklich cool, um nicht zu erwähnen: Sie können dies tun, was hauptsächlich mit Ihrer Frage zusammenhängt:
oder einfach:
quelle
Die
Lazy
Klasse wurde speziell entwickelt, um einen Wert darzustellen, der erst berechnet wird, wenn Sie danach fragen. Sie erstellen es, indem Sie eine Methode bereitstellen, die definiert, wie es erstellt werden soll. Diese Methode wird jedoch nur einmal ausgeführt (selbst wenn mehrere Threads den Wert anfordern) und einfach den bereits erstellten Wert für zusätzliche Anforderungen zurückgeben:quelle
Lazy
dies für Werte verwendet werden sollte, die viel Rechenleistung erfordern, und dass Sie sie nicht für die Interaktion verwenden sollten (da die Semantik.Value
lautet, dass ein Wert zurückgegeben wird, der einer Eigenschaft ähnelt, keine (interaktive) Aktion). Für solche Aktionen sollte stattdessen ein Delegat verwendet werden.Value
wird verwendet; Es ist dasDialogResult
empfangene vom Anzeigen des Meldungsfelds. Der Hauptunterschied zwischen dieser Lösung und der Verwendung eines Delegaten besteht darin, ob der Wert bei jeder Anforderung neu berechnet werden soll oder nicht. Meine Interpretation der Anforderungen war, dass dies konzeptionell einen Wert initialisiert und keine zu wiederholende Operation .Lazy
kann leicht falsch verwendet werden. Es hat Overhead von sich selbst, wenn es "nur" verwendet wird, um eine kleine Aufgabe aufzuschieben, wird mehr Overhead verursacht, als es gewinnt. Das Anzeigen von Nachrichtenfeldern aus einer Eigenschaft ist im Allgemeinen (imo) eine schlechte Praxis, unabhängig davonLazy
. Btw, von MSDN, ich zitiere: „lazy Initialisierung Mit der Schaffung einer großen oder ressourcenintensive Aufgabe verschieben“ . Sie können dem nicht zustimmen, aber dafür wurde es ursprünglich entwickelt.Lazy
in einem solchen Kontext ist sicherlich vernachlässigbar. Es wird blass im Vergleich zu der Zeit, die darauf gewartet wird, dass ein Mensch auf ein Meldungsfeld klickt. Es kommt hauptsächlich auf die tatsächlichen Anforderungen der zugrunde liegenden Anwendung an. Die Unbestimmtheit der Frage macht eine objektiv korrekte Antwort unmöglich. Dies ist eine Interpretation der Frage. Was die Arbeit an einem Immobilienmakler angeht, der schlecht ist; anscheinend bist du grundsätzlich gegen das gesamte design vonLazy
. Sie sind zu dieser Meinung willkommen.MessageBox
der Overhead vernachlässigbar (ich würde die Benutzeroberfläche in einer Eigenschaft einfach nicht verwenden). Ich meinte im Allgemeinen kleine Aufgaben (wie das Verschieben2 + 3 * 4 / i
), bei denen der Aufwand für die Erstellung des Abschlusses größer ist als die Berechnung selbst. Und ich denke, ich bin voll und ganz davon überzeugtLazy
, dass wir es häufig in F # verwenden (etwas weniger in C #) und wir haben auf die harte Weise gelernt, dass man vorsichtig damit sein muss, insb. in Bezug auf die Leistung.Wie ich Ihre Frage lese, steht dies im Zusammenhang mit GUI-Steuerelementen?
Wenn dies in WPF der Fall ist, sehen Sie sich die "richtige" Methode zum Behandeln von Befehlen aus Steuerelementen an: http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx
... aber das kann ein Schmerz und ein Overkill sein. Für einen einfacheren allgemeinen Fall suchen Sie möglicherweise nach einem Ereignishandler wie:
Dieser Ereignishandler kann auf verschiedene Arten behandelt werden. Das obige Beispiel verwendet eine anonyme Funktion, aber Sie können auch Folgendes tun:
... genau wie Sie gefragt haben, mit einer Funktion (oder hier "Aktion", da sie void zurückgibt) als Variable zugewiesen.
quelle
Sie können einer Variablen C # -Code zuweisen, ihn zur Laufzeit kompilieren und den Code ausführen:
Schreiben Sie Ihren Code:
Erstellen Sie den Provider und die Parameter des Compilers:
Parameter des Compilers definieren:
Baugruppe kompilieren:
Fehler überprüfen:
Holen Sie sich Assembly, Typ und die Hauptmethode:
Starte es:
Referenz:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime
quelle