Bir değişken yapmak ve ona bir kod satırı atamak mümkün mü, örneğin:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... bu yüzden değişkeni kullandığımda, kod satırını çalıştıracak.
Bir değişken yapmak ve ona bir kod satırı atamak mümkün mü, örneğin:
ButtonClicked = (MessageBox.Show("Hello, World!"));
... bu yüzden değişkeni kullandığımda, kod satırını çalıştıracak.
Yanıtlar:
Bunu buna Action
benzer bir şekilde atayabilirsiniz :
var ButtonClicked = new Action(() => MessageBox.Show("hi"));
O zaman ara:
ButtonClicked();
Tamlık için (çeşitli yorumlarla ilgili olarak) ...
Erik'in belirttiği gibi, birden çok satır kod çalıştırabilirsiniz:
var ButtonClicked = new Action(() =>
{
MessageBox.Show("hi");
MessageBox.Show("something else"); // something more useful than another popup ;)
});
Tim'in belirttiği gibi, Action
anahtar kelimeyi atlayabilirsiniz.
Action ButtonClicked = () => MessageBox.Show("hi");
Action ButtonClicked = () =>
{
// multiple lines of code
};
Eylem'e gönderebilmek istediğiniz parametrelerin listesini temsil eden boş parantezlerle ilgili KRyan'ın yorumunu ele almak için (bu durumda hiçbiri) .
Örneğin, gösteriye mesajı belirtmek istedim, bir parametre olarak "mesajı" ekleyebilir (ı değiştiğini not Action
etmek tek bir dize parametresi belirtmek amacıyla) :Action<string>
Action<string> ButtonClicked = (message) => MessageBox.Show(message);
ButtonClicked("hello world!");
Action ButtonClicked = () => MessageBox.Show("hi");
eşdeğerdir ve IMO daha güzel (tercih ederseniz parantez ekleyin)
WinForms
?
Button.Click
olaya ekliyorsa ve adını bildiği bir değişkende depolamıyorsa ButtonClicked
.
Sizin durumunuzda, bir delegate
.
Bir temsilcinin nasıl çalıştığını ve konseptini anlayarak daha kolay bir forma nasıl ulaşabileceğimizi görelim:
// Create a normal function
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
// Now we create a delegate called ButtonClick
delegate void ButtonClick();
Gördüğünüz gibi, temsilci normal bir işlev biçimini alır, ancak herhangi bir argüman olmadan (Tıpkı diğer yöntemler gibi herhangi bir sayıda argüman alabilir, ancak basitlik uğruna, öyle değil).
Şimdi elimizdekini kullanalım; Temsilciyi başka herhangi bir değişkeni tanımladığımız gibi tanımlayacağız:
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
Temel olarak ButtonClicked adlı, bir tür ButtonClick (bu bir temsilci) içeren ve kullanıldığında, yöntemi OnButtonClick () yönteminde çalıştıracak yeni bir değişken oluşturduk.
Kullanmak için basitçe ararız:ButtonClicked();
Yani kodun tamamı şöyle olacaktır:
delegate void ButtonClick();
void OnButtonClick()
{
MessageBox.Show("Hello World!");
}
void Foo()
{
ButtonClick ButtonClicked = new ButtonClick(OnButtonClick);
ButtonClicked(); // Execute the function.
}
Buradan lambda ifadelerine geçebilir ve sizin durumunuzda nasıl yararlı olabileceklerini görebiliriz:
.NET kitaplıkları tarafından zaten tanımlanmış birçok delege vardır, bunlardan bazıları Action gibi, herhangi bir parametreyi kabul etmeyen ve bir değer döndürmez. Gibi tanımlanır public delegate void Action();
Her zaman yeni bir Temsilciye her zaman tanımlama ihtiyacı yerine ihtiyaçlarınız için kullanabilirsiniz. Örneğin önceki bağlamda, sadece yazabilirdin
Action ButtonClicked = new Action(OnButtonClick);
ButtonClicked();
bu da aynısını yapardı.
Temsilcileri nasıl kullanacağınıza dair farklı yollar gördüğünüze göre, şimdi ilk lambda ifademizi kullanalım. Lambda ifadeleri anonim işlevlerdir; bu nedenle bunlar normal işlevlerdir, ancak isimsizdir. Bunlar şu biçimlerdendir:
x => DoSomethingWithX(x);
(x) => DoSomethingWithX(x);
(x,y) => DoSometingWithXY(x,y);
() => Console.WriteLine("I do not have parameters!");
Bizim durumumuzda herhangi bir parametremiz yok bu yüzden son ifadeyi kullanacağız. Bunu OnButtonClick işlevi olarak kullanabiliriz, ancak adlandırılmış bir işleve sahip olmamanın avantajını elde ederiz. Bunun yerine şöyle bir şey yapabiliriz:
Action ButtonClicked = new Action( () => MessageBox.Show("Hello World!") );
hatta daha kolay
Action ButtonClicked = () => MessageBox.Show("Hello World!");
O zaman basitçe arayın ButtonClicked();
Elbette çok satırlı kodlarınız da olabilir, ama sizi daha fazla karıştırmak istemiyorum. Yine de şöyle görünecektir:
Action ButtonClicked = () =>
{
MessageBox.Show("Hello World!");
};
ButtonClicked();
Ayrıca etrafta oynayabilirsiniz, örneğin, aşağıdaki gibi bir işlevi çalıştırabilirsiniz:
new Action(() => MessageBox.Show("Hello World!"))();
Uzun gönderi için özür dilerim, umarım çok kafa karıştırıcı değildir :)
DÜZENLEME: Sık kullanılmasa da lambda ifadelerinin anlaşılmasını kolaylaştıran alternatif bir biçimden bahsetmeyi unuttum:
new Action(delegate() {
Console.WriteLine("I am parameterless");
})();
Ayrıca, jenerik kullanarak:
// 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!");
Sırayla lambda ifadelerini kullanabilirsiniz, ancak parametrenin türünü tanımlamanıza gerek yoktur (ancak bazı durumlarda olabilir), örneğin, yukarıdaki kod basitçe şu şekilde yazılabilir:
new Action<string>(x => {
Console.WriteLine(x);
})("I am a string parameter!");
veya:
new Action<string>(x => Console.WriteLine(x))("I am a string parameter!");
EDIT2:
Action<string>
bir temsili olan public void delegate Action(string obj);
Action<string,string>
bir temsilidir public void delegate Action(string obj, string obj2);
Genel olarak, Action<T>
bir temsilidir;public void delegate Action<T>(T obj);
DÜZENLEME3: Yazının bir süredir burada olduğunu biliyorum, ancak bundan bahsetmemek gerçekten harika: Bunu yapabilirsin, ki bu çoğunlukla sorunuzla ilgili:
dynamic aFunction = (Func<string, DialogResult>)MessageBox.Show;
aFunction("Hello, world!");
ya da sadece:
Func<string, DialogResult> aFunction = MessageBox.Show;
aFunction("Hello, world!");
Lazy
Sınıf özellikle bunun için sormak kadar hesaplanan olmayacak bir değeri temsil için tasarlanmıştır. Nasıl inşa edileceğini tanımlayan bir yöntem sağlayarak onu inşa edersiniz, ancak bu yöntemi bir kereden fazla çalıştırmayacaktır (değeri isteyen birden fazla iş parçacığı karşısında bile) ve herhangi bir ek istek için önceden oluşturulmuş değeri döndürerek basitçe gerçekleştirecektir:
var foo = new Lazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));
var result = foo.Value;
Lazy
çok fazla işlem gücü gerektiren değerler için kullanılması gerektiğini ve bunları etkileşim için kullanmamanız gerektiğini unutmayın (çünkü anlamı, .Value
bir özelliğe benzer, bir (etkileşimli) eylem değil bir değer döndürmesidir). Bunun yerine bu tür eylemler için bir temsilci kullanılmalıdır.
Value
edilir kullanılır; o bir DialogResult
mesaj kutusu gösteren alındı. Bu çözüm ile temsilci kullanmak arasındaki temel fark, değerin her istendiğinde yeniden hesaplanması gerekip gerekmediğidir. Gereksinimlerle ilgili yorumum, bunun kavramsal olarak bir değeri başlattığı, tekrarlanacak bir işlem olmadığı şeklindeydi.
Lazy
kolayca yanlış kullanılabilir. Kendi ek yüküne sahiptir, "sadece" küçük bir görevi ertelemek için kullanmak, kazandığından daha fazla ek yük getirecektir. Bir mülkten mesaj kutularının gösterilmesi, ne olursa olsun, genel olarak (imo) kötü bir uygulamadır Lazy
. Btw, MSDN'den alıntı yapıyorum: "Büyük veya kaynak yoğun bir nesnenin oluşturulmasını ertelemek için tembel başlatma kullanın" . Buna katılmayabilirsiniz, ancak başlangıçta bunun için tasarlandı.
Lazy
Böyle bir bağlamda performans ek yükü kesinlikle ihmal edilebilir; bir insanın bir mesaj kutusunu tıklamasını beklemek için harcanan zamana kıyasla soluk olacaktır. Çoğunlukla temeldeki uygulamanın gerçek gereksinimlerine bağlıdır; Sorunun belirsizliği, nesnel olarak doğru bir cevabı imkansız kılar. Bu, sorunun bir yorumudur. Bir mülk alıcısında çok fazla iş yapmanın kötü olmasına gelince; görünüşe göre temelde tüm tasarımına karşısınız Lazy
. Bu fikre hoş geldiniz.
MessageBox
ek yük göz ardı edilebilir (bir mülk içinde UI kullanmam). Genel olarak 2 + 3 * 4 / i
, kapanışı yaratmanın ek yükünün hesaplamanın kendisinden daha büyük olduğu küçük görevleri kastetmiştim (erteleme gibi ). Ve sanırım tamamen kucakladığımı düşünüyorum Lazy
, aslında onu F # dilinde çok kullanıyoruz (C # için biraz daha az) ve buna dikkat etmeniz gerektiğini zor yoldan öğrendik, özellikle. performansla ilgili olarak.
Sorunuzu okuma şeklim, bu GUI kontrolleri bağlamında mı?
Bu WPF'de ise, denetimlerden komutları işlemenin "doğru" yoluna bakın: http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx
... ama bu bir acı ve aşırı öldürme olabilir. Daha basit bir genel durum için, aşağıdaki gibi bir olay işleyicisi arıyor olabilirsiniz:
myButton.Click += (o, e) => MessageBox.Show("Hello, World!");
Bu olay işleyicisi çeşitli şekillerde ele alınabilir. Yukarıdaki örnek, anonim bir işlev kullanır, ancak şunları da yapabilirsiniz:
Action<object, RoutedEventArgs> sayHello = (o, e) => MessageBox.Show("Hello, World");
myButton.Click += new RoutedEventHandler(sayHello);
... tıpkı sizin sorduğunuz gibi, değişken olarak atanmış bir işlevle (veya burada, "Eylem", void döndürdüğü için).
C # kodunu bir değişkene atayabilir, çalışma zamanında derleyebilir ve kodu çalıştırabilirsiniz:
Kodunuzu yazın:
// Assign C# code to the code variable.
string code = @"
using System;
namespace First
{
public class Program
{
public static void Main()
{
" +
"Console.WriteLine(\"Hello, world!\");"
+ @"
}
}
}
";
Derleyicinin sağlayıcısını ve parametrelerini oluşturun:
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
Derleyicinin parametrelerini tanımlayın:
// 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;
Derleme derlemesi:
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
Hataları kontrol edin:
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());
}
Montajı, türü ve Ana yöntemi alın:
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("First.Program");
MethodInfo main = program.GetMethod("Main");
Çalıştırın:
main.Invoke(null, null);
Referans:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime