2008-10-23 18 views
48

Hepimiz C# olayı beyanı olan dehşete aşinayız. parçacığı güvenliği, the standard is to write something like this sağlamak için: C# olaylarını bir uzatma yöntemiyle yükseltmek - bu kötü mü?

public event EventHandler SomethingHappened; 
protected virtual void OnSomethingHappened(EventArgs e) 
{    
    var handler = SomethingHappened; 
    if (handler != null) 
     handler(this, e); 
} 

Son zamanlarda bu tahta (şimdi bulamıyorum olan) bazı diğer söz konusu, birisi yöntemleri bu senaryoda güzel kullanılabileceği uzantıyı dikkat çekti.

public event EventHandler SomethingHappened; 

void SomeMethod() 
{ 
    this.SomethingHappened.RaiseEvent(this, EventArgs.Empty); 
} 

Sorum: yerde bu uzatma yöntemleri sayesinde

static public class EventExtensions 
{ 
    static public void RaiseEvent(this EventHandler @event, object sender, EventArgs e) 
    { 
     var handler = @event; 
     if (handler != null) 
      handler(sender, e); 
    } 
    static public void RaiseEvent<T>(this EventHandler<T> @event, object sender, T e) 
     where T : EventArgs 
    { 
     var handler = @event; 
     if (handler != null) 
      handler(sender, e); 
    } 
} 

bildirmek ve bir olayı yükseltmek için gereken tüm böyle bir şeydir,: İşte bunu yapmak için bir yolu bu iyi bir fikir mi ? Standart On yöntemine sahip olmayla hiçbir şey eksik miyiz? (Fark ettiğim bir şey, açık kod ekleme/çıkarma işlemi olan olaylarla çalışmadığıdır.)

+0

Belki de şu soruyu düşünüyordunuz: http://stackoverflow.com/questions/192980/boiler-plate-code-replacement-is-there-anything-bad-about-this-code – Benjol

cevap

55

Açık bir ekleme/kaldırma işlemine sahip olan olaylarla çalışmaya devam edecek - yalnızca temsilci değişkeni kullanmanız gerekir (veya etkinlik adı yerine delege sakladınız.

Ancak, iş parçacığı güvenli yapmak için daha kolay bir yol var - bir no-op işleyicisi ile başlatılamıyor:

public event EventHandler SomethingHappened = delegate {}; 

önemsiz olacak fazladan bir temsilci çağırarak performans isabet ve emin olur kod daha kolay. Bu arada

, Uzantınız yönteminde ekstra yerel değişkeni gerekmez - tıpkı senin olabilir:

static public void RaiseEvent(this EventHandler @event, object sender, EventArgs e) 
{ 
    if (@event != null) 
     @event(sender, e); 
} 

static public void RaiseEvent<T>(this EventHandler<T> @event, object sender, T e) 
    where T : EventArgs 
{ 
    if (@event != null) 
     @event(sender, e); 
} 

Şahsen bir parametre adı olarak bir anahtar kelimeyi kullanmayı olmaz, ama o değil 't gerçekten hiç çağıran tarafını değiştirmek, böylece :)

DÜZENLEMEYİ istediğini yap: 'XXX üzerindeki' yöntemine gelince: Eğer sınıflar planlıyoruz türetilmiştir? Benim görüşüme göre, çoğu sınıf mühürlenmeli. yapıyorsanız, bu türetilmiş sınıfların olayı yükseltmesini istiyor musunuz? Eğer bu sorulardan birinin cevabı “hayır” ise, o zaman rahatsız olmayın. Her ikisine de cevap "evet" ise o zaman yapın :)

+1

İyi nokta; @event, yönteme dahil olduğunuzda değişemez. Boş bir delegeye abone olabileceğinizi biliyordum, ancak endişem, On yöntemini kullanmanın iyi ya da kötü olup olmadığı konusunda daha fazla ilgiliydi. –

+0

Bu öneriyi, mükemmel kitabınızdan {} temsilci kullanmak için biliyorum! Bu harika :) –

+0

Sınıfınızın delegeyi null olarak ayarladığını hatırla, yine de bir hatanın var. Gerçekten neden bu kadar çok insanın bir problemi olduğunu anlamıyorum. –

3

Daha az kod, daha okunabilir. Benim gibi.

public event EventHandler SomethingHappened = delegate{}; 
1

yerel bir işleyici atayarak "sağlanması" parçacığı güvenliği değiliz: performanstaki ilgilenmiyorsanız

Eğer boş çek kaçınmak için bu gibi olay ilan edebilir değişken. Ödevinizden sonra yönteminiz kesintiye uğramış olabilir. Örneğin olayını dinlemek için kullanılan sınıf kesinti esnasında tanzim edilirse, sen bırakılmış bir sınıfta bir yöntemi diyoruz.

Bir null başvuru özel kendinizi kurtarıyorsun ama orada bunu daha kolay yolları Jon Skeet olarak, ve cevaplarında işaret cristianlibardo.

Başka bir şey olmayan mühürlü sınıflar için, OnFoo yöntemi ben uzatma yöntemleri ile mümkün olduğunu düşünmüyorum hangi sanal olması gerektiğidir.

+0

Bence 'yarış koşullarından kaçınmak' demek istediler. –

5

Sadece tavsiye edilen şekilde bir kez kod yazmak ve onunla yapılabilir [Burada bir düşünce var]. Öyleyse meslektaşlarınızı yanlış bir şey yaptığınızı düşünerek kodun üzerine kafa karıştırmazsınız?

[Daha mesajlar şimdiye kadar bir olay işleyicisi yazmaya harcadığınız daha bir olay işleyicisi yazmaya etrafında yollarını bulmaya çalışan okuyun.]

6

Şimdi C# 6 burada, yangın daha kompakt, evreli bir yolu yoktur bir olay: delegeler (yani o boş değil) olay için kayıtlı olup olmadığını

SomethingHappened?.Invoke(this, e); 

Invoke() sadece null-koşullu operatör sayesinde denir "?".

Sorunun çözümlendiği "işleyici" kodunun iş parçacığı sorunu burada tersine çevrildi çünkü bu kodda olduğu gibi, SomethingHappened yalnızca bir kez erişildiğinden, sınama ve çağırma arasında null olarak ayarlanma olasılığı yok . Bu cevap belki de asıl soruya teğettir, ancak olayları daha basit bir yöntem arayanlar için çok önemlidir.

İlgili konular