![](/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.