[英]C# Weak Event Pattern without changing client code
In .Net 4.0. 在.Net 4.0中。 Is there a way of implementing the Weak Event Pattern using the WeakEventManager so it doesn't require any changes to the client code?
有没有一种使用WeakEventManager实施弱事件模式的方法,因此不需要更改客户端代码?
I want the clients to use standard += to attach to the event: 我希望客户端使用标准+ =附加到事件:
myObject.Updated += new EventHandler(OnUpdated);
However I want it to create a weak event reference. 但是我希望它创建一个弱事件引用。 From the documentation I found I understand I need to create an instance to an IWeakEventListener on the client and use it for attaching
WeakEventManager.AddListener
. 从发现的文档中,我了解到我需要在客户端上的IWeakEventListener创建一个实例,并将其用于附加
WeakEventManager.AddListener
。 Also I need to keep a reference to it on the client otherwise it would be collected by the GC as the WeakEventManger keeps a weak reference to it only. 另外,我需要在客户端上保留对它的引用,否则它将由GC收集,因为WeakEventManger仅保留对它的弱引用。 But that requires changes to the client code which I want to avoid.
但这需要更改我要避免的客户端代码。 Is there any way of doing it by embedding that logic in the event source object (myObject)?
有什么办法可以通过将该逻辑嵌入事件源对象(myObject)中来实现?
This is a .Net 4.0 question. 这是一个.Net 4.0问题。
I've come up with this method but it's not great as it's a lot of code. 我想出了这种方法,但是它不好,因为有很多代码。 Can it be improved?
可以改善吗?
The event holder class: 事件持有人类别:
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;
}
}
}
The WeakEventListener: 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;
}
}
And finally the client code creating a weak event subscription. 最后,客户端代码创建了一个弱事件订阅。
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.