Ist es möglich, eine Variable zu erstellen und ihr eine Codezeile zuzuweisen, z.
ButtonClicked = (MessageBox.Show("Hello, World!"));
... wenn ich die Variable verwende, wird die Codezeile ausgeführt.
Ist es möglich, eine Variable zu erstellen und ihr eine Codezeile zuzuweisen, z.
ButtonClicked = (MessageBox.Show("Hello, World!"));
... wenn ich die Variable verwende, wird die Codezeile ausgeführt.
Antworten:
Sie könnten es einem solchen zuordnen Action
:
var ButtonClicked = new Action(() => MessageBox.Show("hi"));
Dann nenne es:
ButtonClicked();
Der Vollständigkeit halber (in Bezug auf die verschiedenen Kommentare) ...
Wie Erik sagte, können Sie mehrere Codezeilen ausführen:
var ButtonClicked = new Action(() =>
{
MessageBox.Show("hi");
MessageBox.Show("something else"); // something more useful than another popup ;)
});
Wie Tim sagte, könnten Sie das Action
Schlüsselwort weglassen
Action ButtonClicked = () => MessageBox.Show("hi");
Action ButtonClicked = () =>
{
// 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 Action
habe , um einen einzelnen Zeichenfolgenparameter anzugeben) :Action<string>
Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");
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 hat ButtonClicked
.
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 function
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();
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:
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
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:
delegate void ButtonClick();
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
void Foo()
{
ButtonClick ButtonClicked = new ButtonClick(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
Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();
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:
Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );
oder noch einfacher,
Action ButtonClicked = () => MessageBox.Show("Hello World!");
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:
Action ButtonClicked = () =>
{
MessageBox.Show("Hello World!");
};
ButtonClicked();
Sie können auch herumspielen, zum Beispiel eine Funktion wie die folgende ausführen:
new Action(() => 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:
new Action(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.
new Action<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:
new Action<string>(x => {
Console.WriteLine(x);
})("I am a string parameter!");
oder:
new Action<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:
dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");
oder einfach:
Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");
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:
var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));
var result = foo.Value;
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 das DialogResult
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 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.
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 von Lazy
. 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 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.
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:
myButton.Click += (o, e) => MessageBox.Show("Hello, World!");
Dieser Ereignishandler kann auf verschiedene Arten behandelt werden. Das obige Beispiel verwendet eine anonyme Funktion, aber Sie können auch Folgendes tun:
Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);
... genau wie Sie gefragt haben, mit einer Funktion (oder hier "Aktion", da sie void zurückgibt) als Variable zugewiesen.
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:
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
Parameter des Compilers definieren:
// Reference to System.Drawing library
parameters.ReferencedAssemblies.Add("System.Drawing.dll");
// True - memory generation, false - external file generation
parameters.GenerateInMemory = true;
// True - exe file generation, false - dll file generation
parameters.GenerateExecutable = true;
Baugruppe kompilieren:
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
Fehler überprüfen:
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
Holen Sie sich Assembly, Typ und die Hauptmethode:
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
Starte es:
main.Invoke(null, null);
Referenz:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime