Bu sorunun 10 yaşın üzerinde olduğunu anlıyorum, ancak bana sadece en açık cevabın ele alınmadığı gibi değil, belki de sorudan kapakların altında neler olup bittiğini iyi bir şekilde anlayabileceği anlaşılıyor. Buna ek olarak, geç bağlanma ve delegeler ve lambdalar için bunun ne anlama geldiği hakkında başka sorular da var (daha sonra daha fazla).
İlk odası, seçim için 800 lb fil / goril adrese eventvs Action<T>/ Func<T>:
- Bir deyimi veya yöntemi yürütmek için lambda kullanın.
eventYürütülecek birden fazla ifade / lambdas / fonksiyon içeren bir pub / alt modelden daha fazlasını istediğinizde kullanın (bu, yarasadan büyük bir
farktır).
- İfade ağaçlarına ifadeler / işlevler derlemek istediğinizde lambda kullanın. Yansıma ve COM birlikte çalışma gibi daha geleneksel geç bağlama katılmak istediğinizde delege / olay kullanın.
Bir olay örneği olarak, aşağıdaki gibi küçük bir konsol uygulaması kullanarak basit ve 'standart' bir olay kümesi oluşturalım:
public delegate void FireEvent(int num);
public delegate void FireNiceEvent(object sender, SomeStandardArgs args);
public class SomeStandardArgs : EventArgs
{
public SomeStandardArgs(string id)
{
ID = id;
}
public string ID { get; set; }
}
class Program
{
public static event FireEvent OnFireEvent;
public static event FireNiceEvent OnFireNiceEvent;
static void Main(string[] args)
{
OnFireEvent += SomeSimpleEvent1;
OnFireEvent += SomeSimpleEvent2;
OnFireNiceEvent += SomeStandardEvent1;
OnFireNiceEvent += SomeStandardEvent2;
Console.WriteLine("Firing events.....");
OnFireEvent?.Invoke(3);
OnFireNiceEvent?.Invoke(null, new SomeStandardArgs("Fred"));
//Console.WriteLine($"{HeightSensorTypes.Keyence_IL030}:{(int)HeightSensorTypes.Keyence_IL030}");
Console.ReadLine();
}
private static void SomeSimpleEvent1(int num)
{
Console.WriteLine($"{nameof(SomeSimpleEvent1)}:{num}");
}
private static void SomeSimpleEvent2(int num)
{
Console.WriteLine($"{nameof(SomeSimpleEvent2)}:{num}");
}
private static void SomeStandardEvent1(object sender, SomeStandardArgs args)
{
Console.WriteLine($"{nameof(SomeStandardEvent1)}:{args.ID}");
}
private static void SomeStandardEvent2(object sender, SomeStandardArgs args)
{
Console.WriteLine($"{nameof(SomeStandardEvent2)}:{args.ID}");
}
}
Çıktı aşağıdaki gibi görünecektir:

Aynı şeyi Action<int>veya ile Action<object, SomeStandardArgs>de yaparsanız, yalnızca SomeSimpleEvent2ve öğesini görürsünüz SomeStandardEvent2.
Peki içinde neler oluyor event?
Genişletirsek FireNiceEvent, derleyici aslında aşağıdaki üretir (Bu tartışma ile ilgili olmayan iş parçacığı senkronizasyonu ile ilgili bazı ayrıntıları atladım):
private EventHandler<SomeStandardArgs> _OnFireNiceEvent;
public void add_OnFireNiceEvent(EventHandler<SomeStandardArgs> handler)
{
Delegate.Combine(_OnFireNiceEvent, handler);
}
public void remove_OnFireNiceEvent(EventHandler<SomeStandardArgs> handler)
{
Delegate.Remove(_OnFireNiceEvent, handler);
}
public event EventHandler<SomeStandardArgs> OnFireNiceEvent
{
add
{
add_OnFireNiceEvent(value)
}
remove
{
remove_OnFireNiceEvent(value)
}
}
Derleyici, oluşturulduğu sınıf ad alanına görünmeyen özel bir delege değişkeni oluşturur. Bu delege, abonelik yönetimi ve geç bağlayıcı katılım için kullanılan şeydir ve halka açık arayüz, hepimizin tanıdığı ve sevdiği tanıdık +=ve -=operatörlerdir :)
FireNiceEventTemsilci kapsamını korumalı olarak değiştirerek ekleme / kaldırma işleyicileri için kodu özelleştirebilirsiniz . Bu, geliştiricilerin kancalara günlük tutma veya güvenlik kancaları gibi özel kancalar eklemelerine olanak tanır. Bu gerçekten kullanıcı rollerine, vb. Dayalı aboneliğe özelleştirilmiş erişilebilirlik sağlayan bazı çok güçlü özellikler sağlar. Bunu lambdas ile yapabilir misiniz? (Aslında ifade ağaçlarını derleyerek yapabilirsiniz, ancak bu yanıtın kapsamı dışındadır).
Buradaki bazı yanıtlardan birkaç noktayı ele almak için:
'Args listesinin Action<T>değiştirilmesi ile türetilmiş bir sınıfın özelliklerinin değiştirilmesi arasında' kırılganlık 'açısından gerçekten bir fark yoktur EventArgs. Her ikisi de sadece derleme değişikliği gerektirmez, her ikisi de genel bir arabirimi değiştirir ve sürümlendirme gerektirir. Fark yok.
Hangisinin bir endüstri standardı olduğu, bunun nerede ve neden kullanıldığına bağlıdır. Action<T>ve bu genellikle IoC ve DI'da kullanılır ve eventgenellikle GUI ve MQ tipi çerçeveler gibi mesaj yönlendirmede kullanılır. Her zaman değil, sık sık söylediğime dikkat edin .
Delegelerin yaşamları lambdalardan farklı. Kişi de yakalamanın farkında olmalı ... sadece kapanışla değil, aynı zamanda 'kedinin neye sürüklendiğine bak' kavramıyla da. Bu, bellek ayak izini / ömrünü ve aynı zamanda yönetim sızıntılarını da etkiler.
Bir şey daha, daha önce bahsettiğim bir şey ... geç bağlanma kavramı. Bunu bir lambda 'canlı' olduğunda LINQ gibi bir çerçeve kullanırken sıklıkla göreceksiniz. Bu, bir defadan fazla olabilen bir delegenin geç bağlanmasından çok farklıdır (yani lambda her zaman oradadır, ancak bir lambda'nın aksine, isteğe bağlı olarak talep üzerine sıklıkla gerçekleşir) - sihir gitti ve yöntem (ler) / özellik (ler) her zaman bağlanacaktır. Akılda tutulması gereken bir şey.