Czy można utworzyć zmienną i przypisać do niej wiersz kodu, taki jak:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... więc kiedy używam zmiennej, wykona linię kodu.
Czy można utworzyć zmienną i przypisać do niej wiersz kodu, taki jak:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... więc kiedy używam zmiennej, wykona linię kodu.
Odpowiedzi:
Możesz go przypisać do Action
takiego:
var ButtonClicked = new Action(() => MessageBox.Show("hi"));
Następnie nazwij to:
ButtonClicked();
Dla kompletności (w odniesieniu do różnych uwag) ...
Jak stwierdził Erik, możesz wykonać wiele wierszy kodu:
var ButtonClicked = new Action(() =>
{
MessageBox.Show("hi");
MessageBox.Show("something else"); // something more useful than another popup ;)
});
Jak stwierdził Tim, możesz pominąć Action
słowo kluczowe
Action ButtonClicked = () => MessageBox.Show("hi");
Action ButtonClicked = () =>
{
// multiple lines of code
};
Aby odnieść się do komentarza KRyana, dotyczącego pustych nawiasów, który reprezentuje listę parametrów, które chcesz wysłać do akcji (w tym przypadku żadnych) .
Jeśli, na przykład, chcesz określić komunikat do wyświetlenia, możesz dodać „komunikat” jako parametr (zwróć uwagę, że zmieniłem Action
na , aby określić pojedynczy parametr ciągu) :Action<string>
Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");
Action ButtonClicked = () => MessageBox.Show("hi");
jest równoważny i ładniejszy IMO (dodaj parens, jeśli wolisz)
WinForms
?
Button.Click
wydarzenia i nie przechowuje go w zmiennej, którą przypadkiem nazwał ButtonClicked
.
W twoim przypadku chcesz użyć delegate
.
Zobaczmy, jak działa delegat i jak możemy dostać się do łatwiejszej formy, rozumiejąc jego koncepcję:
// Create a normal function
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();
Widzisz, delegat ma postać normalnej funkcji, ale bez żadnych argumentów (może przyjąć dowolną liczbę argumentów, tak jak każda inna metoda, ale dla uproszczenia tak nie jest).
Teraz użyjmy tego, co mamy; zdefiniujemy delegata tak samo, jak definiujemy każdą inną zmienną:
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
Zasadniczo stworzyliśmy nową zmienną o nazwie ButtonClicked, która ma typ ButtonClick (który jest delegatem) i która, gdy zostanie użyta, wykona metodę w metodzie OnButtonClick ().
Aby z niego skorzystać, po prostu dzwonimy:ButtonClicked();
Więc cały kod wyglądałby tak:
delegate void ButtonClick();
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
void Foo()
{
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
ButtonClicked(); // Execute the function.
}
Stąd możemy przejść do wyrażeń lambda i zobaczyć, jak mogą być przydatne w twojej sytuacji:
istnieje wiele delegatów już zdefiniowanych przez biblioteki .NET, z niektórymi takimi jak Action, które nie akceptują żadnego parametru i nie zwracają wartości. Jest zdefiniowany w ten public delegate void Action();
sposób, że zawsze możesz go użyć do swoich potrzeb, zamiast potrzeby definiowania za każdym razem nowego delegata. Na przykład w poprzednim kontekście mógłbyś po prostu napisać
Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();
który zrobiłby to samo.
Teraz, gdy znasz już różne sposoby używania delegatów, użyjmy naszego pierwszego wyrażenia lambda. Wyrażenia lambda to funkcje anonimowe; są to więc normalne funkcje, ale bez nazwy. Są to formy:
x => DoSomethingWithX(x);
(x) => DoSomethingWithX(x);
(x,y) => DoSometingWithXY(x,y);
() => Console.WriteLine("I do not have parameters!");
W naszym przypadku nie mamy żadnych parametrów, więc użyjemy ostatniego wyrażenia. Możemy tego użyć tak samo jak funkcji OnButtonClick, ale mamy tę zaletę, że nie mamy nazwanej funkcji. Zamiast tego możemy zrobić coś takiego:
Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );
lub nawet łatwiej,
Action ButtonClicked = () => MessageBox.Show("Hello World!");
następnie po prostu zadzwoń. ButtonClicked();
Oczywiście możesz również mieć wiele linii kodu, ale nie chcę cię bardziej mylić. Wyglądałoby to jednak tak:
Action ButtonClicked = () =>
{
MessageBox.Show("Hello World!");
};
ButtonClicked();
Możesz też pobawić się, na przykład, możesz wykonać taką funkcję:
new Action(() => MessageBox.Show("Hello World!"))();
Przepraszamy za długi post, mam nadzieję, że nie był zbyt zagmatwany :)
EDYCJA: Zapomniałem wspomnieć, że alternatywna forma, która, choć rzadko używana, może ułatwić zrozumienie wyrażeń lambda:
new Action(delegate() {
Console.WriteLine("I am parameterless");
})();
Ponadto, używając typów ogólnych:
// 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!");
Z kolei możesz użyć wyrażeń lambda, ale nie musisz (ale w niektórych przypadkach może) definiować typ parametru, na przykład powyższy kod można po prostu zapisać jako:
new Action<string>(x => {
Console.WriteLine(x);
})("I am a string parameter!");
lub:
new Action<string>(x => Console.WriteLine(x))("I am a string parameter!");
EDIT2:
Action<string>
jest reprezentacją public void delegate Action(string obj);
Action<string,string>
jest reprezentacją public void delegate Action(string obj, string obj2);
Ogólnie Action<T>
jest reprezentacjąpublic void delegate Action<T>(T obj);
EDIT3: Wiem, że post był tu od jakiegoś czasu, ale myślę, że naprawdę fajnie jest nie wspominać: Możesz to zrobić, co jest głównie związane z twoim pytaniem:
dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");
lub po prostu:
Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");
Lazy
Klasa jest specjalnie zaprojektowany, aby reprezentować wartości, które nie będą obliczane aż o to poprosić. Konstruujesz go, dostarczając metodę, która definiuje, jak powinna być skonstruowana, ale poradzi sobie z wykonaniem tej metody nie więcej niż raz (nawet w obliczu wielu wątków żądających wartości) i po prostu zwraca już skonstruowaną wartość dla wszelkich dodatkowych żądań:
var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));
var result = foo.Value;
Lazy
powinno być używane dla wartości, które wymagają dużej mocy obliczeniowej i że nie powinieneś ich używać do interakcji (ponieważ semantyka .Value
jest taka, że zwraca wartość podobną do właściwości, a nie do (interaktywnej) akcji). Zamiast tego do takich działań należy użyć delegata.
Value
jest wartość ; jest to DialogResult
otrzymane z wyświetlenia okna komunikatu. Podstawowa różnica między tym rozwiązaniem a użyciem delegata polega na tym, czy wartość powinna być ponownie obliczana za każdym razem, gdy jest żądana, czy nie. Moja interpretacja wymagań była taka, że jest to koncepcyjna inicjalizacja wartości, a nie operacja do powtórzenia.
Lazy
można łatwo niewłaściwie wykorzystać. Ma na sobie narzut, a użycie go „tylko” do odroczenia małego zadania spowoduje większe obciążenie niż zyskuje. Pokazywanie skrzynek wiadomości z właściwości jest ogólnie złą praktyką (imo), niezależnie od tego Lazy
. Przy okazji, z MSDN cytuję: „Użyj leniwej inicjalizacji, aby odroczyć tworzenie dużego lub wymagającego dużej ilości zasobów obiektu” . Możesz się z tym nie zgodzić, ale do tego pierwotnie był przeznaczony.
Lazy
w takim kontekście jest z pewnością pomijalny; blednie w porównaniu z czasem spędzonym na czekaniu, aż człowiek kliknie okno wiadomości. Sprowadza się to głównie do rzeczywistych wymagań aplikacji bazowej; niejasność pytania uniemożliwia obiektywnie poprawną odpowiedź. To jest jedna interpretacja pytania. Jeśli chodzi o wykonywanie dużej ilości pracy w celu uzyskania złej własności; najwyraźniej zasadniczo sprzeciwiasz się całemu projektowi Lazy
. Zapraszamy do tej opinii.
MessageBox
narzut jest znikomy (po prostu nie użyłbym interfejsu użytkownika wewnątrz nieruchomości). Miałem na myśli ogólnie małe zadania (takie jak odraczanie 2 + 3 * 4 / i
), w których narzut związany z utworzeniem zamknięcia jest większy niż same obliczenia. I myślę, że w pełni to rozumiem Lazy
, w rzeczywistości używamy go dużo w F # (trochę mniej w C #) i na własnej skórze nauczyliśmy się, że trzeba z tym uważać, szczególnie. w odniesieniu do wydajności.
Sposób, w jaki czytam twoje pytanie, czy to w kontekście elementów sterujących GUI?
Jeśli to jest w WPF, spójrz na „właściwy” sposób obsługi poleceń z formantów: http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx
... ale to może być bólem i przesadą. Dla prostszego przypadku ogólnego możesz szukać programu obsługi zdarzeń, takiego jak:
myButton.Click += (o, e) => MessageBox.Show("Hello, World!");
Ten program obsługi zdarzeń można obsługiwać na różne sposoby. Powyższy przykład używa funkcji anonimowej, ale możesz też zrobić:
Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);
... tak jak pytałeś, z funkcją (lub tutaj „Action”, ponieważ zwraca void) przypisaną jako zmienna.
Możesz przypisać kod C # do zmiennej, kompilując ją w czasie wykonywania i uruchamiając kod:
Wpisz swój kod:
// Assign C# code to the code variable.
string code = @"
using System;
namespace First
{
public class Program
{
public static void Main()
{
" +
"Console.WriteLine(\"Hello, world!\");"
+ @"
}
}
}
";
Utwórz dostawcę i parametry kompilatora:
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
Zdefiniuj parametry kompilatora:
// 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;
Skompiluj montaż:
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
Sprawdź błędy:
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());
}
Uzyskaj montaż, typ i metodę główną:
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
Uruchom:
main.Invoke(null, null);
Odniesienie:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime