我正在编写一个简单的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());
}
}
}
问题是我在.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
对我来说,调用不应该是模棱两可的,编译器应该更喜欢泛型任务而不是非泛型任务,特别是因为它是GetCustomerNamesAsync()
的输出。但是,作为一名VB.NET开发人员,我可能在这种情况下依赖Option Infer
。
我如何明确地让编译器知道我希望它在C#中使用哪个调用?
答案 0 :(得分:10)
尝试显式指定lambda参数类型,如下所示:
.ContinueWith((Task<string[]> t) => { ... })
您调用它的方式存在的问题是Task<TResult>
和Task
(它的基类)都有ContinueWith
方法看起来几乎相同:
Task<TResult>.ContinueWith(Action<Task<TResult>> action)
Task<TResult>.ContinueWith(Action<Task> action) //inherited from `Task`
如果不指定action
的输入类型,编译器无法确定您想要的过载。明确提供action
lambda的输入参数类型可以解决这种歧义。
如果编译器可以假定采用Action<Task<TResult>> action
的版本,那肯定会很好。也许其他人对如何获得这种行为有所了解?
在评论中你会看到MCattle发现他只是遇到了这个问题,因为在lambda内部的方法调用中有一些编译器奇怪与丢失的括号有关。通常,在将lambda传递给Task<TResult>
时,您不需要显式指定ContinueWith
类型。