在 C# 中将 Func<int, int> 传递给 Task.Run() 而不使用 lambda 表达式

Passing a Func<int, int> to Task.Run() in C# without using lambda expressions

我试图了解 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() 与普通的旧简单对象一起使用?

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() { ... }
    }
    

我怀疑您希望避免使用匿名方法或 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 表达式时需要的闭包,所以我真的看不出这样做有什么意义就这样对我来说,更难阅读的代码似乎是额外的工作。

但也许您更喜欢直白。如果是这样,以上内容将可以满足您的要求。