在参数中使用2参数定义的操作委托

时间:2014-01-23 12:08:49

标签: c# generics lambda

鉴于这些定义:

public ICommand OkCommand { get; set; }

public ModelCommand(Action<object> execute)

public RelayCommand(Action<T> execute)

此代码编译:

this.OkCommand = new ModelCommand(x => this.Ok(this, new EventArgs()));

this.OkCommand = new RelayCommand<ThisType>(x => this.Ok(this, new EventArgs()));

this.OkCommand = new RelayCommand<EventArgs>(x => this.Ok(this, new EventArgs()));

但是我很困惑,为什么这个编译以及我是否理解正确 在这两种情况下,Action方法都有1个in参数,而函数this.Ok有2个。 参数如何处理Action委托,接收哪个参数以及为什么?

4 个答案:

答案 0 :(得分:1)

但是你的构造函数只取一个参数 - 它被称为x。你可以翻译:

RelayCommand<EventArgs>(x => this.Ok(this, new EventArgs()));

成:

RelayCommand<EventArgs>(delegate(EventArgs x)
{
    this.Ok(this, new EventArgs());
});

甚至:

RelayCommand<EventArgs>(SomeTemporaryDelegate);

public void SomeTemporaryDelegate(EventArgs x)
{
    this.Ok(this, new EventArgs());
}

这可能会澄清事情。您只是不使用x委托内部,使用外部变量作为参数。

答案 1 :(得分:1)

每个Action都接受一个参数,在这种情况下,参数在执行时传递给命令的命令参数。因此,在以下情况下:

this.OkCommand = new RelayCommand<EventArgs>(x => this.Ok(this, new EventArgs()));

x将是EventArgs个实例。该操作对参数没有任何作用,只是直接调用Ok,尽管它也可以写成:

this.OkCommand = new RelayCommand<EventArgs>(x => this.Ok(this, x));

看起来Ok的格式为EventArgs,因为它是第二个参数

对于:

是一样的
this.OkCommand = new RelayCommand<ThisType>(x => this.Ok(this, new EventArgs()));

它需要一个ThisType commanand参数,并且不执行任何操作。

如果你正在使用标准的RelayCommand类,那么就会有一个非泛型版本只需要一个无参数Action,这样你就可以写:

this.OkCommand = new RelayCommand(() => this.Ok(this, x));

这可能更清楚,因为它表明你对命令参数不感兴趣。

答案 2 :(得分:1)

this.OkCommand = new ModelCommand(x => this.Ok(this, new EventArgs()));

在这种情况下,当您调用this.OkCommand();

  • 将调用ModelCommand委托,其中:
  • 将评估其表达式,
  • 将评估表达式中包含的Ok调用,
  • 将评估呼叫中包含的参数,
  • 将评估this,这是一个“闭包”(即,已捕获的变量),作为封闭对象和new EventArgs()

tl; dr:当您调用OkCommand时,您不会直接致电Ok。相反,OkCommand会调用RelayCommand,其中包含正确调用Ok所需的所有信息。

答案 3 :(得分:1)

编写匿名委托或lambda表达式时,可以使用当前作用域中的任何成员,而不仅仅是传递给方法的参数。编译器创建一个闭包,它捕获lambda执行所需的一切。

因此,您的代码大致翻译为:

private class MyClass
{
    public MyClass()
    {
        var closure = new <>c__DisplayClass1 { _this = this };
        OkCommand = new ModelCommand(new Action<object>(closure.b__0));
    }

    [CompilerGenerated]
    private sealed class <>c__DisplayClass1
    {
        public MyClass _this;

        public void b__0(object o)
        {
            return _this.Ok(_this, new EventArgs());
        }
    }
}

b__0方法与Action<object>签名匹配,生成的类包含您在lambda中引用的所有字段。

由于这种行为,闭包扩展了其中捕获的字段的范围,因此您必须知道将lambda发送到的位置,否则您可能会遇到不必要的内存泄漏。