gpt4 book ai didi

c# - 确定何时将 lambda 编译为实例方法

转载 作者:太空狗 更新时间:2023-10-29 23:16:19 24 4
gpt4 key购买 nike

前言:我试图在这里非常准确地描述场景。 TL;DR version 是“我如何判断一个 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);
}

现在上面的一切都很好,我明白了为什么它以前不起作用,以及改变它是如何让它起作用的。但是,我剩下的是一些东西,这意味着我现在编写的代码必须根据我不知道的编译器决定在风格上有所不同。

所以,我的问题是 - 这是在所有情况下都有记录的行为 - 或者行为是否会根据编译器的 future 实现而改变?我是否应该忘记尝试使用 lambda 并始终将实例方法传递给 RelayCommand ?或者我应该有一个约定,即 Action 总是缓存到一个实例成员中:

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.

-> 甚至没有指定它生成任何方法这一事实。

在这种情况下,我会选择命名方法而不是匿名方法。如果那不可能,因为您需要从注册命令的方法访问变量,您应该使用上次显示的代码。


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

关于c# - 确定何时将 lambda 编译为实例方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13800629/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com