![](/img/trans.png)
[英]Why is the implementation of events in C# not using a weak event pattern by default?
[英]C# Weak Event Pattern without changing client code
在.Net 4.0中。 有沒有一種使用WeakEventManager實施弱事件模式的方法,因此不需要更改客戶端代碼?
我希望客戶端使用標准+ =附加到事件:
myObject.Updated += new EventHandler(OnUpdated);
但是我希望它創建一個弱事件引用。 從發現的文檔中,我了解到我需要在客戶端上的IWeakEventListener創建一個實例,並將其用於附加WeakEventManager.AddListener
。 另外,我需要在客戶端上保留對它的引用,否則它將由GC收集,因為WeakEventManger僅保留對它的弱引用。 但這需要更改我要避免的客戶端代碼。 有什么辦法可以通過將該邏輯嵌入事件源對象(myObject)中來實現?
這是一個.Net 4.0問題。
我想出了這種方法,但是它不好,因為有很多代碼。 可以改善嗎?
事件持有人類別:
public class GotWeakEvent
{
// Keeps strong references to the IWeakEventListeners until it's
// identified that the handlers are gone (GC collected). The check happens when
// the event is raised or a handler is detached.
// If it's never raised an nothing detaches then it leaks
// the WeakReference objects and the listeners.
private readonly List<Tuple<WeakReference, WeakEventListener>> _listeners = new List<Tuple<WeakReference, WeakEventListener>>();
private event EventHandler InternalMyWeakEvent;
public event EventHandler MyWeakEvent
{
add
{
WeakEventListener l = new WeakEventListener(value);
WeakReference wr = new WeakReference(value);
lock (_listeners)
{
_listeners.Add(new Tuple<WeakReference, WeakEventListener>(wr, l));
}
PrivateManager.AddListener(this, l);
}
remove
{
// remove the reference from the listeners list
lock (_listeners)
{
for (int i = _listeners.Count - 1; i >= 0; i--)
{
var tuple = _listeners[i];
if (!tuple.Item1.IsAlive)
{
_listeners.RemoveAt(i);
}
else if ((EventHandler)tuple.Item1.Target == value)
{
PrivateManager.RemoveListener(this, tuple.Item2);
_listeners.RemoveAt(i);
}
}
}
}
}
protected void RaiseMyWeakEvent()
{
// clear dead references
lock (_listeners)
{
for (int i = _listeners.Count - 1; i >= 0; i--)
{
var tuple = _listeners[i];
if (!tuple.Item1.IsAlive)
{
_listeners.RemoveAt(i);
}
}
}
var handler = InternalMyWeakEvent;
if (handler == null) return;
handler(this, new EventArgs());
}
private class PrivateManager : WeakEventManager
{
private static PrivateManager CurrentManager
{
get
{
var managerType = typeof(PrivateManager);
var manager = GetCurrentManager(managerType) as PrivateManager;
if (manager != null) return manager;
manager = new PrivateManager();
SetCurrentManager(managerType, manager);
return manager;
}
}
public static void AddListener(GotWeakEvent source, IWeakEventListener listener)
{
CurrentManager.ProtectedAddListener(source, listener);
}
public static void RemoveListener(GotWeakEvent source, IWeakEventListener listener)
{
CurrentManager.ProtectedRemoveListener(source, listener);
}
protected override void StartListening(object source)
{
((GotWeakEvent)source).InternalMyWeakEvent += DeliverEvent;
}
protected override void StopListening(object source)
{
((GotWeakEvent)source).InternalMyWeakEvent -= DeliverEvent;
}
}
}
WeakEventListener:
public class WeakEventListener : IWeakEventListener
{
private readonly WeakReference _handlerReference;
public WeakEventListener(EventHandler handler)
{
if (handler == null) throw new ArgumentNullException("handler");
_handlerReference = new WeakReference(handler);
}
public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
EventHandler handler = _handlerReference.Target as EventHandler;
if (handler == null) return false;
handler(sender, e);
return true;
}
}
最后,客戶端代碼創建了一個弱事件訂閱。
GotWeakEvent source = new GotWeakEvent();
// [....]
// normal usage but it's weak
source.MyWeakEvent += OnMyWeakEvent;
private void OnMyWeakEvent(object sender, EventArgs e)
{
// do the stuff
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.