gpt4 book ai didi

c# - 带有构造函数参数的 lambda 的 RelayCommand

转载 作者:行者123 更新时间:2023-12-03 10:42:53 26 4
gpt4 key购买 nike

如果在 XAML 文件中,我将 Button 绑定(bind)到来自以下类的“Command”,则单击 Button 不会导致执行 DoIt:

class Thing()
{
public Thing(Foo p1)
{
Command = new RelayCommand(() => DoIt(p1));
}

private DoIt(Foo p)
{
p.DoSomething();
}

public ICommand Command { get; private set; }
}

但是,如果我从 p1 初始化一个字段并将该字段作为参数传递给 lambda 内的方法调用,它确实有效:
class Thing()
{
private Foo field;
public Thing(Foo p1)
{
field = p1;
Command = new RelayCommand(() => DoIt(field));
}

private DoIt(Foo p)
{
p.DoSomething();
}

public ICommand Command { get; private set; }
}

为什么前者失败,但后者按预期工作?

可能相关: How do closures work behind the scenes? (C#)

编辑:为了澄清,以下内容也适用于我。但是,我仍然想知道为什么第二个示例达到了我的预期,而第一个没有。
class Thing()
{
private Foo field;
public Thing(Foo p1)
{
field = p1;
Command = new RelayCommand(DoIt);
//Command = new RelayCommand(() => DoIt()); Equivalent?
}

private DoIt()
{
field.DoSomething();
}

public ICommand Command { get; private set; }
}

最佳答案

这是一个老问题,但我最近偶然发现了这个话题,值得回答。

这种奇怪行为的原因源于 RelayCommand 的 MVVM Light 实现。 . execute 和 canexecute 处理程序存储为 WeakAction _executeWeakFunc<bool> _canExecute在中继命令中。 WeakAction当由于某种原因该命令仍被 UI 引用时,尝试允许对 View 模型进行 GC 清理。

跳过一些细节,底线是:将 View 模型方法分配为处理程序效果很好,因为 WeakAction只要 View 模型还活着,它就会一直活着。对于动态创建的 Action ,情况不同。如果对该操作的唯一引用在 RelayCommand ,只存在一个弱引用,GC可以随时收集 Action ,翻整个RelayCommand变成一 block 死砖。

好的,是时候了解详细信息了。 WeakAction的执行不是盲目地存储对 Action 的弱引用——这会导致许多引用消失。相反,弱 Delegate.Target 的组合引用和 Delegate.MethodInfo被储存了。对于静态方法,该方法将通过强引用存储。

现在,这导致了三类 lambda:

  • 静态方法:() => I_dont_access_anything_nonstatic()将存储为强引用
  • 成员变量的关闭:() => DoIt(field)闭包方法将在 viewmodel 类中创建, Action 目标是 viewmodel,只要 viewmodel 保持事件状态,它就会保持事件状态。
  • 局部变量的关闭:() => DoIt(p1)闭包将创建一个单独的类实例来存储捕获的变量。这个单独的实例将成为操作目标,不会有任何强引用 - GC 会在某个时候清理

  • 重要提示:据我所知,Roslyn 可能会改变这种行为: Delegate caching behavior changes in Roslyn因此,今天使用案例 (2) 的工作代码有可能变成使用 Roslyn 的非工作代码。但是,我没有测试这个假设,它可能会完全不同。

    关于c# - 带有构造函数参数的 lambda 的 RelayCommand,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46811428/

    26 4 0