在旧计算机上工作的ReactiveExtension现在失败了

本文关键字:失败 ReactiveExtension 工作 计算机 | 更新日期: 2023-09-27 18:30:31

我正在使用 .Net 中弱事件中的代码,这是处理对可观察集合的监视更改的简单方法。该代码几个月来一直没有任何问题。 我最近更新了一台新计算机。 设置完所有内容并从存储库中提取代码后,我遇到了一个奇怪的问题。 代码不再有效!

这是我代码的相关部分,它都发生在构造函数中:

 public class PurchaseOrderReceipt : BaseEntity
{
    /// <summary>
    ///     Initializes a new instance of the <see cref="PurchaseOrderReceipt" /> class.
    /// </summary>
    public PurchaseOrderReceipt()
    {
        this.ReceiptItems = new ObservableCollection<PurchaseOrderItemReceipt>();
        this.DateReceived = DateTime.Now;
        this.ReceiptItems.ObserveCollectionChanged()
            .SubscribeWeakly(this, (target, eventArgs) => target.ReceiptItemsChanged());
    }

异常在 SubscribeWeakly 行上引发,并显示以下错误消息:ArgumentException:onNext 必须引用静态方法,否则订阅仍将保留对目标的强引用

我可以通过创建 PurchaseOrderReceipts 的实例在 LinqPad 中重现该问题。

如果我在 LinqPad 中编写一个简单的类来镜像 PurchaseOrderReceipt 类中的设置,那就更奇怪了。

LinqPad 代码:

void Main()
{
    var x = new Test(); 
    x.ReceiptItems.Add(new PurchaseOrderItemReceipt());
}
public class Test:BaseEntity
{
    public ObservableCollection<PurchaseOrderItemReceipt> ReceiptItems {get; set;}
    public Test()
    {
        this.ReceiptItems = new ObservableCollection<PurchaseOrderItemReceipt>();
        this.ReceiptItems.ObserveCollectionChanged().SubscribeWeakly(this,(target, eventargs) => target.TestChanged());
    }
    private void TestChanged()
    {
        "Changed!".Dump();
    }
}

已更改!在结果窗口中打印出来。

这是顶部链接中的 CustomReactiveExtension 类。

public static class CustomReactiveExtension
    {
        public static IObservable<EventPattern<NotifyCollectionChangedEventArgs>> ObserveCollectionChanged(this INotifyCollectionChanged collection)
        {
            return Observable.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
                handler => (sender, e) => handler(sender, e),
                handler => collection.CollectionChanged += handler,
                handler => collection.CollectionChanged -= handler);
        }
        public static IDisposable SubscribeWeakly<T, TTarget>(this IObservable<T> observable, TTarget target, Action<TTarget, T> onNext) where TTarget : class
        {
            var reference = new WeakReference(target);
            if (onNext.Target != null)
            {
                throw new ArgumentException("onNext must refer to a static method, or else the subscription will still hold a strong reference to target");
            }
            IDisposable subscription = null;
            subscription = observable.Subscribe(item =>
            {
                var currentTarget = reference.Target as TTarget;
                if (currentTarget != null)
                {
                    onNext(currentTarget, item);
                }
                else
                {
                    subscription.Dispose();
                }
            });
            return subscription;
        }
    }

有什么想法吗?

在旧计算机上工作的ReactiveExtension现在失败了

我不是 100% 确定,但我的猜测是,不同版本的编译器或不同的编译选项会导致您的 lambda 被编译为实例方法而不是静态方法。

最简单的解决方案是显式实现一个静态方法以用作onNext回调,即:

private static void OnReceiptItemsChanged(PurchaseOrderReceipt target, 
    EventPattern<NotifyCollectionChangedEventArgs> eventPattern)
{
    // TODO Do something here
}

然后像这样使用SubscribeWeakly

this.ReceiptItems.ObserveCollectionChanged().SubscribeWeakly(this, OnReceiptItemsChanged);

现在,无论您使用哪个编译器或哪个编译选项,回调始终是静态方法。