2013-05-22 13 views
6

Sto scrivendo una semplice applicazione di console C# che utilizza Asynchronous Tasks ed Entity Framework (con l'intento di eseguirlo su Linux (RHEL) con Mono, ma questa è un'altra sfida). Si noti che sto prendendo come destinazione .NET 4.0, quindi sto utilizzando .ContinueWith() anziché await.Invocazione ambigua su Generic Continue con il

Questo, più il modello EF DB di un database Northwind, è la totalità della richiesta:

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()); 
     } 

    } 
} 

Il problema è che sto ottenendo il seguente errore al .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 

Per me, l'invocazione non dovrebbe essere ambigua, il compilatore dovrebbe preferire l'attività generica sull'Attività non generica, specialmente perché è l'output di GetCustomerNamesAsync(). Tuttavia, come sviluppatore VB.NET, probabilmente mi affido a Option Infer in questa situazione.

Come farei esplicitamente a lasciare che il compilatore sappia quale invocazione voglio che usi in C#?

risposta

10

provare a specificare in modo esplicito il tipo di parametro lambda, come questa:

.ContinueWith((Task<string[]> t) => { ... }) 

Questo problema con il modo in cui si stava chiamando è che Task<TResult> e Task (la sua classe base) entrambi hanno un metodo ContinueWith che sembra quasi il stessa:

Task<TResult>.ContinueWith(Action<Task<TResult>> action) 
Task<TResult>.ContinueWith(Action<Task> action) //inherited from `Task` 

senza specificare il tipo di ingresso del action, il compilatore non può determinare quali sovraccaricate si desidera. Fornendo esplicitamente il tipo di parametro di input di lambda action, questa ambiguità viene ripristinata.


Certamente sarebbe bello se il compilatore potrebbe assumere la versione che prende Action<Task<TResult>> action. Forse qualcun altro ha un'idea su come ottenere quel tipo di comportamento?


Ai posteri ...

Nei commenti vedrai che MCattle trovato che stava solo incontrando questo problema a causa di qualche compilatore stranezza relativa a parentesi mancanti su una chiamata di metodo all'interno del suo lambda . In generale, non è necessario specificare esplicitamente il tipo Task<TResult> quando si passa il lambda a ContinueWith.

+2

Mi hai portato alla soluzione giusta. Dichiarare esplicitamente '.ContinueWith ((Task t) => {...})' poi ha smascherato il problema successivo, che stavo chiamando 'Console.WriteLine (t.Exception.Flatten.ToString)' invece di 'Console.WriteLine (t.Exception.Flatten(). ToString()) '. Dopo aver corretto questo, sono stato in grado di rimuovere la dichiarazione del parametro lambda esplicito e il compilatore era felice. – MCattle

+1

@MCattle Interessante che le parentesi mancanti potrebbero rendere il compilatore incapace di decidere tra i due overload. Ero un po 'sospettoso della mia risposta, perché non ricordavo di dover dare esplicitamente il tipo di input lambda all'infinito numero di volte in cui ho usato 'ContinueWith'. Non so spiegare perché le parentesi mancanti farebbero la differenza. –

+1

Ha senso per me, perché il sovraccarico è dedotto dall'utilizzo e se c'è un errore di sintassi nell'utilizzo, non è possibile dedurre il sovraccarico corretto. – MCattle