+1 za rzadkie połączenie bycia nowicjuszem w programowaniu i zadawania dobrego pytania: rozumiesz, co chcesz zrobić i dobrze to wyjaśniasz, po prostu nie znasz na to terminu, więc nie możesz go znaleźć samodzielnie.
stackoverflow.com/questions/6187944/… sprawdź to, myślę, że jest wystarczająco dużo wyjaśnień, których będziesz potrzebować. Asp działa prawie jak winform w tej kwestii.
Dla kompletności (w odniesieniu do różnych uwag) ...
Jak stwierdził Erik, możesz wykonać wiele wierszy kodu:
varButtonClicked=newAction(()=>{MessageBox.Show("hi");MessageBox.Show("something else");// something more useful than another popup ;)});
Jak stwierdził Tim, możesz pominąć Actionsłowo kluczowe
ActionButtonClicked=()=>MessageBox.Show("hi");ActionButtonClicked=()=>{// 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 Actionna , aby określić pojedynczy parametr ciągu) :Action<string>
Action ButtonClicked = () => MessageBox.Show("hi");jest równoważny i ładniejszy IMO (dodaj parens, jeśli wolisz)
Tim S.,
1
Możliwe jest również, że akcja zostanie rozwiązana do więcej niż jednej linii kodu.
Erik Philips,
2
@CSharpie Nie jestem pewien, czy przyjęcie tego założenia jest pomocne dla OP.
Erik Philips,
2
@CSharpie Dlaczego OP nie mógł tego użyć WinForms?
vivat pisces
2
@CSharpie Rozumiem, co mówisz. Jeśli faktycznie dołącza to do Button.Clickwydarzenia i nie przechowuje go w zmiennej, którą przypadkiem nazwał ButtonClicked.
vivat pisces
51
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 functionvoidOnButtonClick(){MessageBox.Show("Hello World!");}// Now we create a delegate called ButtonClickdelegatevoidButtonClick();
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ą:
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:
delegatevoidButtonClick();voidOnButtonClick(){MessageBox.Show("Hello World!");}voidFoo(){ButtonClickButtonClicked=newButtonClick(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ć
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:
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:
Możesz też pobawić się, na przykład, możesz wykonać taką funkcję:
newAction(()=>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:
newAction(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.newAction<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:
newAction<string>(x =>{Console.WriteLine(x);})("I am a string parameter!");
lub:
newAction<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:
LazyKlasa 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 =newLazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));var result = foo.Value;
Pamiętaj, że Lazypowinno być używane dla wartości, które wymagają dużej mocy obliczeniowej i że nie powinieneś ich używać do interakcji (ponieważ semantyka .Valuejest 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.
Abel
1
@Abel Nie, to nie jest dla wartości, które wymagają dużej mocy obliczeniowej, ale dla każdej wartości, o którą chciałbyś odroczyć inicjalizację, dopóki nie zostanie o nią poproszona, ale nigdy nie inicjalizujesz tej wartości więcej niż raz. Tutaj używana Valuejest wartość ; jest to DialogResultotrzymane 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.
Servy
Lazymoż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.
Abel
1
@Abel Narzut wydajności Lazyw 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.
Servy
Przepraszam, musiałeś mnie źle zrozumieć. Z pewnością 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.
Abel
4
Sposób, w jaki czytam twoje pytanie, czy to w kontekście elementów sterujących GUI?
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!\");"+@"
}
}
}
";
Odpowiedzi:
Możesz go przypisać do
Action
takiego:Następnie nazwij to:
Dla kompletności (w odniesieniu do różnych uwag) ...
Jak stwierdził Erik, możesz wykonać wiele wierszy kodu:
Jak stwierdził Tim, możesz pominąć
Action
słowo kluczoweAby 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>
źródło
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ę:
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ą:
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:
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ć
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:
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:
lub nawet łatwiej,
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:Możesz też pobawić się, na przykład, możesz wykonać taką funkcję:
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:
Ponadto, używając typów ogólnych:
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:
lub:
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:
lub po prostu:
źródło
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ń:źródło
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 toDialogResult
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 tegoLazy
. 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 projektowiLazy
. 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 odraczanie2 + 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 rozumiemLazy
, 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:
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ć:
... tak jak pytałeś, z funkcją (lub tutaj „Action”, ponieważ zwraca void) przypisaną jako zmienna.
źródło
Możesz przypisać kod C # do zmiennej, kompilując ją w czasie wykonywania i uruchamiając kod:
Wpisz swój kod:
Utwórz dostawcę i parametry kompilatora:
Zdefiniuj parametry kompilatora:
Skompiluj montaż:
Sprawdź błędy:
Uzyskaj montaż, typ i metodę główną:
Uruchom:
Odniesienie:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime
źródło