在不使用Lambda表达式的情况下将Func <int,int =“”>传递给C#中的Task.Run()

时间:2019-03-21 05:24:02

标签: c# lambda parameters task func

我尽力了解C#的Task / Func / Action / await功能,但仍需要您的帮助:

我的gui线程中有一个按钮单击事件处理程序,该事件处理程序在调用时会执行以下操作:

Func<int> t = new Func<int>(CountToBillion);
int result = await Task.Run(t);
//do something with result value...

方法本身声明为:

private int CountToBillion()
{
    //count to 1 billion and return 0
}

到目前为止,此操作没有错误。但是,如果我想将参数传递给CountToBillion(),我尝试的一切都会出错。

Func<int, int> t = new Func<int, int>(CountToBillion);
int result = Task.Run(t???);
// ...
private int CountToBillion(int workerId)
{
    //count to 1 billion and return 0
}

目前,我不想使用lambda表达式,因为我还不了解它们。我总是看到这个解决方案:

await Task.Run(() => methodcall(...));

但是没有lambda表达式就必须使用它,否则我在这里完全偏离了轨道吗?我如何将Task.Run()与简单的旧对象一起使用?

2 个答案:

答案 0 :(得分:1)

Task.Run方法没有重载,因此您可以使用Func<T, R>

  1. 您可以使用闭包,但这只是您出于实践的考虑而不想使用的内容:

    var someInput = 42;
    
    // And there are side-effects to calling the Result property getter
    // but that's a totally different issue I am ignoring for now
    // because it depends on the application context
    var result = Task.Run(() => CountToBillion(someInput)).Result;
    
  2. 因此,请重新构建代码。做C#编译器对闭包所做的事情。手动进行转换。

    因此,不必像这样编写CountToBillion方法:

    public static void Main(string[] args)
    {
    }
    
    static int CountToBillion(int someInput) { ... }
    

    执行以下操作:

    public static void Main(string[] args)
    {
      var foo = new Foo(42);
      var result = Task.Run(foo.CountToBillion).Result;
    }
    
    class Foo
    {
      public Foo(int someInput) { SomeInput = someInput; }
      public int SomeInput { get; set; }
      public int CountToBillion() { ... }
    }
    

答案 1 :(得分:1)

我对您希望避免使用匿名方法或lambda表达式表示怀疑。它们很方便,惯用,并且在功能上您将完成本质上相同的操作,但是没有编译器的帮助。

我认为,您可以阅读Task.Run()文档以及任何其他文档,因此您可以轻松地看到该方法没有任何重载,该方法提供了任务委托的参数化调用。因此,您需要自己提供。

如果您愿意使用lambda表达式,则可以完全按照C#编译器为您执行的方式进行操作。特别是,您需要声明一个类型来保存参数,并且该类型具有用于任务调用的合适方法。

例如:

class CountToBillionWrapper
{
    private readonly int _workerId;

    public CountToBillionWrapper(int workerId)
    {
        _workerId = workerId;
    }

    public int CountToBillion()
    {
        // do whatever, using the _workerId field as if it had been passed to the method
    }
}

然后您可以执行以下操作:

CountToBillionWrapper wrapper = new CountToBillionWrapper(workerId);

int result = await Task.Run(wrapper.CountToBillion);    

因为从本质上讲,这是C#编译器如何实现使用lambda表达式捕获要传递给方法的变量时所需的闭包,所以我不明白这样做的意义办法。似乎需要更多工作才能让我更难读的代码。

但是也许您更喜欢露骨。如果是这样,上面的方法可以满足您的要求。