编程语言
首页 > 编程语言> > c# – 确定将lambda编译为实例方法的时间

c# – 确定将lambda编译为实例方法的时间

作者:互联网

前言:我试图在这里非常精确地描述这个场景. TL; DR版本是’如何判断lambda是否会编译成实例方法或闭包’…

我在我的WPF项目中使用MvvmLight,并且该库最近更改为使用WeakReference实例以保存传递给RelayCommand的操作.因此,实际上,我们有一个对象,它将WeakReference保存到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’语法),它都保持活动状态.

但是,现在,因为它保存在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);
}

现在上面的一切都很好,我理解为什么它以前不起作用,以及如何改变它导致它工作.但是,我留下的东西意味着我现在编写的代码必须在风格上有所不同,这取决于我不知情的编译器决策.

所以,我的问题是 – 在所有情况下这是一个记录在案的行为 – 或者行为是否会根据编译器的未来实现而改变?我应该忘记尝试使用lambdas并始终将实例方法传递给RelayCommand吗?或者我应该有一个约定,其中操作始终缓存到实例成员:

Action<ReportTypeSelected> _commandAction;
ctor(Guid token)
{
    _commandAction = x => Messenger.Default.Send(x, token);
    Command = new RelayCommand(_commandAction);
}

任何背景阅读指针也非常感谢!

解决方法:

无论您最终会在当前类上使用新类还是实例方法,都是您不应该依赖的实现细节.

从C#规范,第7.15.2章(强调我的):

It is explicitly unspecified whether there is any way to execute the block of an anonymous function other than through evaluation and invocation of the lambda-expression or anonymous-method-expression. In particular, the compiler may choose to implement an anonymous function by synthesizing one or more named methods or types.

– &GT甚至没有指定它根本生成任何方法的事实.

鉴于这种情况,我会使用命名方法而不是匿名方法.如果那是不可能的,因为你需要从注册命令的方法中访问变量,你应该使用你最后显示的代码.

在我看来,将RelayCommand更改为使用WeakReference的决定很糟糕.它创造了比解决的问题更多的问题.

标签:c,closures,lambda,mvvm-light
来源: https://codeday.me/bug/20190520/1143930.html