对通用ContinueWith的模糊调用

MCa*_*tle 6 generics lambda asynchronous task-parallel-library c#-4.0

我正在编写一个简单的C#控制台应用程序,该应用程序使用异步任务和实体框架(意图使用Mono在Linux(RHEL)下运行它,但这是另一个挑战).请注意,我的目标是.NET 4.0,所以我使用的是.ContinueWith()代替await.

这个以及Northwind数据库的EF DB模型是整个应用程序:

using System;
using System.Linq;
using System.Threading.Tasks;

namespace MonoEF
{
    class Program
    {
        private static Model.NorthwindEntities _db = new Model.NorthwindEntities();

        static void Main(string[] args)
        {
            try
            {
                GetCustomerNamesAsync().ContinueWith(t => {
                    if (t.IsFaulted) Console.WriteLine(t.Exception.Flatten.ToString);
                        else if (t.IsCompleted) foreach (string result in t.Result) Console.WriteLine(result);
                    });

                Console.ReadLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        private static Task<string[]> GetCustomerNamesAsync()
        {
            return Task.Factory.StartNew(() => (from c in _db.Customers select c.ContactName).Distinct().ToArray());
        } 

    }
}
Run Code Online (Sandbox Code Playgroud)

问题是我在以下错误中收到以下错误.ContinueWith():

Ambiguous Invocation:
  System.Threading.Tasks.Task.ContinueWith(System.Action<System.Threading.Tasks.Task<string[]>>) (in class Task<string[]>)
  System.Threading.Tasks.Task.ContinueWith(System.Action<System.Threading.Tasks.Task>) (in class Task)
match
Run Code Online (Sandbox Code Playgroud)

对我来说,调用不应该是模糊的,编译器应该优先于非泛型Task上的泛型Task,尤其是它的输出GetCustomerNamesAsync().但是,作为一名VB.NET开发人员,我可能Option Infer在这种情况下依赖.

我如何明确地让编译器知道我希望它在C#中使用哪个调用?

Tim*_*lds 10

尝试显式指定lambda参数类型,如下所示:

.ContinueWith((Task<string[]> t) => { ... })
Run Code Online (Sandbox Code Playgroud)

你调用它的方式存在的问题是(Task<TResult>Task它的基类)都有一个ContinueWith看起来几乎相同的方法:

Task<TResult>.ContinueWith(Action<Task<TResult>> action)
Task<TResult>.ContinueWith(Action<Task> action) //inherited from `Task`
Run Code Online (Sandbox Code Playgroud)

如果不指定输入类型action,编译器无法确定所需的过载.明确地提供actionlambda的输入参数类型可以解决这种歧义.


如果编译器可以采用所采用的版本,那肯定会很好Action<Task<TResult>> action.也许其他人对如何获得这种行为有所了解?


后人......

在评论中你会看到MCattle发现他只是遇到了这个问题,因为一些编译器奇怪与他在lambda内的方法调用中缺少括号有关.通常,Task<TResult>在将lambda传递给时,您不需要显式指定类型ContinueWith.

  • 你引导我找到正确的解决方案.明确声明`.ContinueWith((Task <string []> t)=> {...})`然后解除下一个问题,即我调用`Console.WriteLine(t.Exception.Flatten.ToString)`而不是`Console.WriteLine(t.Exception.Flatten().的ToString())`.修复此问题后,我能够删除显式的lambda参数声明,编译器很高兴. (2认同)