前言:我试图在这里非常准确地描述这个场景。版本是“TL;DR
我如何判断 lambda 将被编译为实例方法还是闭包”......
我在我的 WPF 项目中使用 MvvmLight,并且该库最近更改为使用WeakReference
实例来保存传递到RelayCommand
. 所以,实际上,我们在某处有一个对象,它持有 aWeakReference
到 a Action<T>
。
现在,自从升级到最新版本后,我们的一些命令停止了工作。我们有一些这样的代码:
ctor(Guid token)
{
Command = new RelayCommand(x => Messenger.Default.Send(x, token));
}
这导致生成一个关闭(如果我没有使用正确的术语,请纠正我)类 - 像这样:
[CompilerGenerated]
private sealed class <>c__DisplayClass4
{
public object token;
public void <.ctor>b__0(ReportType x)
{
Messenger.Default.Send<ReportTypeSelected>(new ReportTypeSelected(X), this.token);
}
}
这在以前工作得很好,因为操作存储在RelayCommand
实例中,并且无论它被编译为实例方法还是闭包(即使用'<>DisplayClass'语法)都保持活动状态。
但是,现在,因为它保存在 a 中WeakReference
,所以代码仅在指定的 lambda 编译为实例方法时才有效。这是因为闭包类被实例化,传递到RelayCommand
几乎立即进行垃圾收集,这意味着当命令开始使用时,没有要执行的操作。因此,必须修改上面的代码。将其更改为以下原因,例如:
Guid _token;
ctor(Guid token)
{
_token = token;
Command = new RelayCommand(x => Messenger.Default.Send(x, _token));
}
这会导致编译后的代码产生一个成员 - 如下所示:
[CompilerGenerated]
private void <.ctor>b__0(ReportType x)
{
Messenger.Default.Send<ReportTypeSelected>(new ReportTypeSelected(X), this._token);
}
现在上述一切都很好,我明白为什么它以前不起作用,以及改变它是如何导致它起作用的。然而,我剩下的东西意味着我现在编写的代码必须根据我不知情的编译器决定在风格上有所不同。
所以,我的问题是- 这是在所有情况下都有记录的行为 - 还是行为会根据编译器的未来实现而改变?我是否应该忘记尝试使用 lambda 并始终将实例方法传递给RelayCommand
? 或者我应该有一个约定,即动作总是被缓存到一个实例成员中:
Action<ReportTypeSelected> _commandAction;
ctor(Guid token)
{
_commandAction = x => Messenger.Default.Send(x, token);
Command = new RelayCommand(_commandAction);
}
任何背景阅读指针也很感激地接受!