使用操作和任务

时间:2015-12-09 04:17:19

标签: c# task-parallel-library

我想传递一个方法,该方法返回 void 并接受一个param int 。我该怎么做?

有人能告诉我非lambda和lambda版本吗?

        private void LongTask(int s)
        {

            Thread.Sleep(s* 1000);
        }


        public void Run()
        {
            Task q = Task.Run(Action<int>(LongTask));

        }

1 个答案:

答案 0 :(得分:1)

在您的示例中,您尚未显示要传递给方法的值。这让人有点难以确定你甚至在问什么。但我您要求说明如何调用方法LongTask(),并将其作为Task.Run()操作传递给适当的值,并使用两者进行说明lambda语法和非lambda语法。

注意:这一点实际上并非特定于Task.Run()。这一切都适用于您处理将委托传递给一个方法的任何时候,该方法需要使用与您调用的方法中使用的签名不同的签名来表示方法。这里涉及的Task.Run()几乎是偶然的。

总之...

实际上,由于lambda表达式(在此用法中)编译为匿名方法,因此实际上有三个选项:

“老派”匿名方法:

public void Run()
{
    int someValue = 17;

    Task q = Task.Run(delegate { LongTask(someValue); });
}

以上导致编译器创建匿名方法(delegate() { LongTask(someValue); }),并生成代码以创建委托实例以传递给Task.Run()方法。委托的类型是根据用法推断出来的(即基于与匿名方法声明匹配的一个方法重载)。

Lambda匿名方法:

public void Run()
{
    int someValue = 17;

    Task q = Task.Run(() => LongTask(someValue));
}

上面的内容与上一个示例类似,只是使用名义上更简洁的lambda语法来声明匿名方法。我说“名义上”,因为在这个特殊情况下,它并没有那么短。但是还有其他场景,lambda语法更方便;通常,当匿名方法返回一个值时,由于使用lambda语法,return语句是隐式的。

<强>显

class A
{
    private readonly int _value;
    private readonly Action<int> _action;

    public A(int value, Action<int> action)
    {
        _value = value;
        _action = action;
    }

    public void M() { _action(_value); }
}

public void Run()
{
    int someValue = 17;

    Task q = Task.Run((Action)(new A(someValue, LongTask).M));
}

上面依赖于一个显式编写的类来实现与匿名方法选项导致的编译器生成的类相同的目的。根据具体情况,编译器生成的类在实现中可能有很大不同。但是行为基本上是相同的:创建了一个类的实例,其中存储了所需的值,并且类中包含了相应签名的方法,其中该方法的主体是您要执行的代码

(旁白:在这种情况下,为了简明起见,我展示了一个实际上需要委托实例而不是对目标对象和方法调用进行硬编码的实现。这实际上是一个比编译器实际上会生成,主要是因为编译器必须处理更复杂的场景,这是一个仅在非常狭窄的场景中有用的优化,即只有一个方法被调用。编译器也会存储{{1并且会根据需要使用存储的this引用和任何其他捕获的变量将复制匿名方法的主体到生成的方法,例如调用this方法)。

在上面,变量LongTask()_value,但在匿名方法中,它们通常是从匿名方法的上下文中捕获的可变变量。为了更好地模拟匿名方法通常如何工作,你需要更像这样的东西:

readonly

请注意,在上文中,class A { public int value; private readonly Action<int> _action; public A(int value, Action<int> action) { this.value = value; _action = action; } public void M() { _action(value); } } public void Run() { A a = new A(17, LongTask); Task q = Task.Run((Action)a.M); a.value = 19; } 是公共字段。并且代码在调用value后实际修改了变量。这类似于在匿名方法示例中更改Task.Run()的值(再次,在调用someValue之后),并且具有相同的风险:如果Task.Run()方法之后的赋值在之前执行任务可以执行方法调用,然后传递给方法的值不同于任务可以先执行方法。

道德:始终关注您捕获的变量,并确保它们具有您期望它们具有的生命周期和价值。


顺便说一下,在最后两个示例中需要转换为所需的委托类型Task.Run(),因为否则选择的Action重载对编译器来说是不明确的,在Task.Run()和{{之间1}}。简短版本:尝试从方法组转换为委托类型并将其与特定重载匹配时,将忽略委托签名的返回类型。对于较长的版本,请参阅Compiler Ambiguous invocation error - anonymous method and method group with Func<> or Action