2011-01-20 44 views
3

我有一個MulticastDelegate可以引用具有相同簽名的許多(遺留)委託之一。例如:使用MulticastDelegate作爲參數,同時避免DynamicInvoke

public delegate void ObjectCreated(object sender, EventArgs args); 
public delegate void ObjectDeleted(object sender, EventArgs args); 
//... 

這些代表隨後被用來定義事件:

public event ObjectCreated ObjectWasCreated; 
public event ObjectDeleted ObjectWasDeleted; 

然後我有這需要在MulticastDelegate,我用它來執行一些常規的檢查方法:

void DispatchEvent(MulticastDelegate handler, object sender, EventArgs args) 
{ 
    if (handler != null) 
    { 
     // ... 
     handler.DynamicInvoke(sender, args); 
    } 
} 

從類別的其他方法中調用,其中事件被定義爲:

DispatchEvent(ObjectWasCreated, sender, args); 
DispatchEvent(ObjectWasDeleted, sender, args); 

是否有更簡潔的方法來避免DynamicInvoke?

+1

該遺留代碼升級到EventHandler的時間。在那之前,沒有。 – 2011-01-20 21:53:32

+0

真正的代碼不是直接使用`EventArgs`,而是使用自定義的子類。然而,我看不到任何理由不應該爲每個分派的事件使用相同的委託 - 然後我可以從MulticastDelegate更改爲有問題的委託類型。 – 2011-01-21 16:43:51

回答

2

這裏是我的無反射解決方案。它基本上實現了一個多播委託作爲一個列表。較少的代碼?不,更好的表現?我不知道。清潔器?咩。

public delegate void ObjectCreated(object sender, EventArgs args); 
public delegate void ObjectDeleted(object sender, EventArgs args); 

public event ObjectCreated ObjectWasCreated 
{ 
    add 
    { 
     m_ObjectCreatedSubscribers.Add(value.Invoke); 
    } 
    remove 
    { 
     m_ObjectCreatedSubscribers.RemoveAll(e => e.Target.Equals(value)); 
    } 
} 
public event ObjectDeleted ObjectWasDeleted 
{ 
    add 
    { 
     m_ObjectDeletedSubscribers.Add(value.Invoke); 
    } 
    remove 
    { 
     m_ObjectDeletedSubscribers.RemoveAll(e => e.Target.Equals(value)); 
    } 
} 

private List<Action<object, EventArgs>> m_ObjectCreatedSubscribers = new List<Action<object, EventArgs>>(); 
private List<Action<object, EventArgs>> m_ObjectDeletedSubscribers = new List<Action<object, EventArgs>>(); 

void DispatchEvent(List<Action<object, EventArgs>> subscribers, object sender, EventArgs args) 
{ 
    foreach (var subscriber in subscribers) 
     subscriber(sender, args); 
} 
+0

嗯,它不是更簡潔,但它避免了反思和動態調用,並教會我一些新的東西,所以謝謝! – 2011-01-21 16:49:49

0

你可以這樣做:

void DispatchEvent(MulticastDelegate handler, object sender, EventArgs args) 
{ 
    EventHandler eventHandler = 
     (EventHandler)Delegate.CreateDelegate(typeof(EventHandler), handler.GetType().GetMethod("Invoke")); 

    eventHandler(sender, args); 
} 

我不知道這是否會比使用DynamicInvoke更快,雖然。

你必須在某處使用反射。如果每個代表可以保證只有一個用戶,那麼您可以在創建EventHandler時直接使用Delegate.Method屬性,但由於它們是事件,它們很可能有多個用戶...

+0

-1。這對幫助OP有何幫助?他沒有`EventHandler`類型,而是自定義的代表。 – nawfal 2013-06-04 08:42:26

1

一個簡單的替代方法是使用內置的類型,如Action<,>EventHandler而不是定製的代表,讓你得到強大的類型。

public static event Action<object, EventArgs> ObjectWasCreated; 
public static event Action<object, EventArgs> ObjectWasDeleted; 

void DispatchEvent(Action<object, EventArgs> handler, object sender, EventArgs args) 
{ 
    if (handler != null) 
    { 
     // ... 
     handler(sender, args); 
    } 
} 

public static event EventHandler ObjectWasCreated; 
public static event EventHandler ObjectWasDeleted; 

void DispatchEvent(EventHandler handler, object sender, EventArgs args) 
{ 
    if (handler != null) 
    { 
     // ... 
     handler(sender, args); 
    } 
} 

現在你的方法調用將是直接的。

DispatchEvent(ObjectWasCreated, sender, args); 
DispatchEvent(ObjectWasDeleted, sender, args); 

但這大多不是一個好的解決方案。

你可以使用dynamic,仍遠優於DynamicInvoke

void DispatchEvent(MulticastDelegate handler, object sender, EventArgs args) 
{ 
    if (handler != null) 
    { 
     // ... 
     ((dynamic)handler)(sender, args); 
    } 
} 

或可能是仿製藥:

void DispatchEvent<T>(T handler, object sender, EventArgs args) 
{ 
    if (handler != null) 
    { 
     // ... 
     ((dynamic)handler)(sender, args); 
    } 
} 

我做了一個小的性能對比,發現dynamic太好實際:

對於百萬試圖

MulticastDelegate +動態(第一實例)=> 40毫秒

通用+動態(第二實例)=> 90毫秒

MulticastDelegate + DynamicInvoke(在問題給出最初) => 940毫秒