C# 弱化远程执行-反馈请求

C# 弱化远程执行-反馈请求,c#,.net,delegates,garbage-collection,C#,.net,Delegates,Garbage Collection,我刚刚在.NET中实现了一个WeakEventDelegate类 我曾在和中看到过其他文章,大意是要实现这样一个目标 然而,我所实现的实现没有那么复杂(尽管不那么灵活),而且似乎可以完成这项工作,所以我想知道是否有我遗漏的东西 除了相对缺乏灵活性外,以下实现是否存在任何问题 public class WeakEventDelegate<TEventArgs> where TEventArgs : EventArgs { private readonly WeakRe

我刚刚在.NET中实现了一个
WeakEventDelegate

我曾在和中看到过其他文章,大意是要实现这样一个目标

然而,我所实现的实现没有那么复杂(尽管不那么灵活),而且似乎可以完成这项工作,所以我想知道是否有我遗漏的东西

除了相对缺乏灵活性外,以下实现是否存在任何问题

public class WeakEventDelegate<TEventArgs> 
    where TEventArgs : EventArgs
{
    private readonly WeakReference handlerReference;

    public WeakEventDelegate(Action<object, TEventArgs> handler)
    {
        handlerReference = new WeakReference(handler);
    }

    public void Handle(object source, TEventArgs e)
    {
        Action<object, TEventArgs> unwrappedHandler = (Action<object, TEventArgs>)handlerReference.Target;
        if (unwrappedHandler != null)
        {
            unwrappedHandler.Invoke(source, e);
        }
    }
}
我会写:

private readonly WeakDelegate<CustomEventArgs> _customHandler = new WeakDelegate<CustomEventArgs>(this.HandleCustomEvent);
void subscribe()
{
    publisher.RaiseCustomEvent += _customHandler.Handle;
}
private readonly WeakDelegate\u customHandler=new WeakDelegate(this.HandleCustomEvent);
无效订阅()
{
publisher.RaiseCustomEvent+=\u customHandler.Handle;
}

我想到的该类的主要用例是一些集合类(订阅者),它们的生命周期我几乎无法控制。(但是,其中一种情况发生在WPF数据绑定中,因此它是使用推荐的弱事件基础结构的完美候选)。

这里的主要问题是,订阅您的代理(
handlerReference.Target
)的任何内容都将保持
handlerReference
的活动状态

将其包装为您提供了在不保留对委托的引用的情况下调用委托的方法,但不会阻止订户保持引用的活动性


框架所支持的功能是通过有一个中介来实现的。订阅是通过中介处理的,等式的两边都是通过弱引用来维护的。没有任何东西可以直接引用委托-因为对委托的引用可以使对象保持活动状态。

我发现该实现存在一个关键问题-只有在其他地方保留对委托(构造函数中传递的处理程序)的引用时,它才起作用。否则,该委托对象将被收集,事件将不再触发。

我喜欢在处理事件的类一侧实现弱委托的想法,因为我不希望只有在某些情况下才有弱引用。对于我的个人ui框架,我有时会对事件做出反应,而不保留对原始对象的引用:

void HandlePropertyChanged(Object sender, PropertyChangedArgs args)
{
    // Do some stuff with the sender
}
这需要非弱代理,而其他对象需要弱代理

解决方案 我遇到了与您相同的问题,并通过对代理不使用
WeakReference
而对代理的目标使用
WeakReference
并复制空代理来解决了这些问题

// Create a weak reference to the target
_Sender = new WeakReference(target.Target);
_CallDelegate = (Action<TThis, TSender, TArgs>)Delegate.CreateDelegate(CallDelegateType, target.Method);

正如您所看到的,仍然存在一个问题:
WeakDelegate
在以后需要删除事件时必须保留在内存中。对此也有一个解决方案,但它需要覆盖
WeakDelegate
的相等方法,并将所有委托存储在一个哈希表中,这可能会大大降低应用程序的速度。

弱事件的一个主要问题是,如果订阅列表包含对订阅服务器的唯一引用,事件发布者无法知道是否有任何内容关心该事件。从根本上说,只要存在对任何将由事件处理程序修改的内容的引用,事件就应该保持活动状态,但事件发布者无法知道这些引用是否存在或可能采用何种形式

另一种方法是让每个事件订阅者传递对实现适当事件通知接口的对象的引用,并让该接口包含一个属性,该属性指示订阅者是否仍然对事件感兴趣。添加事件订阅时,事件发布者有时会轮询订阅者,查看他们是否仍然感兴趣;这些操作可以方便地逐段或批处理完成,但每个添加的订阅的平均订阅轮询操作数应以常量为界


请注意,现有的事件基础结构在弱引用情况下工作得相当糟糕,因为重复添加和放弃未触发事件的订阅服务器可能会通过持有死引用的对象创建任意大的订阅列表,没有给这些对象一个清理自己的机会。

如果我理解正确,这里的风险是订阅者可能会决定直接钩住代理,而不是通过弱引用钩住代理,这对我来说很好;正如我在编辑中所解释的,目标只是防止对委托的引用垃圾收集发布者对象。发布者可以决定直接(通过handlerReference.Target)钩住事件这一事实并不是问题,因为它在绑定事件时已经可以直接钩住事件了。
// Create a weak reference to the target
_Sender = new WeakReference(target.Target);
_CallDelegate = (Action<TThis, TSender, TArgs>)Delegate.CreateDelegate(CallDelegateType, target.Method);
_RemoveMethod = (Action<DataEventHandler<TSender, TArgs>>)Delegate.CreateDelegate(AddMethodType, eventHolder, eventDeclaration.GetRemoveMethod());
n.Disposing += (_DisposeDelegate = new WeakDelegate<Drawable, IComponent,Object>(n, "Disposing", HandleRootDisposing));