在旧计算机上运行的 ReactiveExtension 现在失败了
ReactiveExtension that was working on old computer is now failing
我正在使用 Weak Events in .Net, the easy way 中的代码来处理对可观察集合的监视更改。该代码几个月来一直没有任何问题。我最近更新到一台新电脑。在完成所有设置并从我的存储库中提取代码后,我遇到了一个奇怪的问题。该代码不再有效!
这是我的代码的相关部分,全部发生在构造函数中:
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 必须引用静态方法,否则订阅仍将持有对目标的强引用
我可以通过创建 PurchaseOrderReceipt 的实例在 LinqPad 中重现该问题。
如果我在 LinqPad 中编写一个简单的 class 来反映 PurchaseOrderReceipt class 中的设置,那么它仍然很奇怪。
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();
}
}
变了!结果打印出来window.
这是顶部 link 中的 CustomReactiveExtension class。
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;
}
}
有什么想法吗?
我不是 100% 确定,但我的猜测是不同版本的编译器或不同的编译选项导致您的 lambda 被编译为实例方法而不是静态方法。
最简单的解决方案是显式实现一个静态方法用作您的 onNext
回调,即:
private static void OnReceiptItemsChanged(PurchaseOrderReceipt target,
EventPattern<NotifyCollectionChangedEventArgs> eventPattern)
{
// TODO Do something here
}
然后像这样使用 SubscribeWeakly
:
this.ReceiptItems.ObserveCollectionChanged().SubscribeWeakly(this, OnReceiptItemsChanged);
现在无论您使用哪个编译器或哪个编译选项,回调始终是静态方法。
我正在使用 Weak Events in .Net, the easy way 中的代码来处理对可观察集合的监视更改。该代码几个月来一直没有任何问题。我最近更新到一台新电脑。在完成所有设置并从我的存储库中提取代码后,我遇到了一个奇怪的问题。该代码不再有效!
这是我的代码的相关部分,全部发生在构造函数中:
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 必须引用静态方法,否则订阅仍将持有对目标的强引用
我可以通过创建 PurchaseOrderReceipt 的实例在 LinqPad 中重现该问题。
如果我在 LinqPad 中编写一个简单的 class 来反映 PurchaseOrderReceipt class 中的设置,那么它仍然很奇怪。
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();
}
}
变了!结果打印出来window.
这是顶部 link 中的 CustomReactiveExtension class。
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;
}
}
有什么想法吗?
我不是 100% 确定,但我的猜测是不同版本的编译器或不同的编译选项导致您的 lambda 被编译为实例方法而不是静态方法。
最简单的解决方案是显式实现一个静态方法用作您的 onNext
回调,即:
private static void OnReceiptItemsChanged(PurchaseOrderReceipt target,
EventPattern<NotifyCollectionChangedEventArgs> eventPattern)
{
// TODO Do something here
}
然后像这样使用 SubscribeWeakly
:
this.ReceiptItems.ObserveCollectionChanged().SubscribeWeakly(this, OnReceiptItemsChanged);
现在无论您使用哪个编译器或哪个编译选项,回调始终是静态方法。