C#弱事件模式,无需更改客户端代码
在.NET4.0中。是否有一种方法可以使用WeakEventManager实现弱事件模式,从而不需要对客户端代码进行任何更改 我希望客户端使用standard+=附加到事件:C#弱事件模式,无需更改客户端代码,c#,.net,C#,.net,在.NET4.0中。是否有一种方法可以使用WeakEventManager实现弱事件模式,从而不需要对客户端代码进行任何更改 我希望客户端使用standard+=附加到事件: myObject.Updated += new EventHandler(OnUpdated); 但是,我希望它创建一个弱事件引用。从中,我了解到我需要在客户端上为IWeakEventListener创建一个实例,并将其用于附加WeakEventManager.AddListener。此外,我需要在客户端上保留对它的引用
myObject.Updated += new EventHandler(OnUpdated);
但是,我希望它创建一个弱事件引用。从中,我了解到我需要在客户端上为IWeakEventListener创建一个实例,并将其用于附加WeakEventManager.AddListener
。此外,我需要在客户端上保留对它的引用,否则它将由GC收集,因为较弱的VentManger只保留对它的弱引用。但这需要对客户端代码进行更改,我希望避免这样做。有没有办法将该逻辑嵌入事件源对象(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;
}
}
}
最后是创建弱事件订阅的客户端代码
GotWeakEvent source = new GotWeakEvent();
// [....]
// normal usage but it's weak
source.MyWeakEvent += OnMyWeakEvent;
private void OnMyWeakEvent(object sender, EventArgs e)
{
// do the stuff
}
编写事件的添加和删除访问器,您可以在其中调用add/RemoveHandler。WeakEventManager的.Net 4.0版本没有AddHandler方法。它只有void ProtectedAddListener(对象源,IWeakEventListener listener)。如果使用强引用将代码存储在
\U listeners
中,则中的\U处理程序
将提供强引用,并破坏代码的用途。请参阅subscriber
保持活动状态,即使您的弱事件在哪里工作,它也应该有资格收集。但是tuple.Item1.IsAlive
永远不会为false<代码>元组.Item2.\u处理程序
使其保持活动状态。你不会有任何软弱的听众行为。从my pastebin链接运行测试程序,如果您的程序正在运行,则两个结果中的一个应为false
,如果两者都为true
,则表示某个内容包含强引用,无法收集该项。以下是粘贴的更新版本:如果您的程序正常运行弱事件处理程序只有第一个结果将是true
,如果它像您说的那样工作,只有前两个或三个结果将是true
,但是如果您运行它,所有四个结果都返回true
,订阅者永远不会被收集。您是对的,刚刚意识到它。我更新了WeakEventListener,以保存对处理程序的弱引用。你看到其他问题了吗?是的,你的最新更新犯的错误和我在回复中发布并删除的错误相同。使用my Second pastebin运行您的程序,您的程序将抛出FatalExecutionEngineError
异常。
GotWeakEvent source = new GotWeakEvent();
// [....]
// normal usage but it's weak
source.MyWeakEvent += OnMyWeakEvent;
private void OnMyWeakEvent(object sender, EventArgs e)
{
// do the stuff
}