6

私は、非同期タスクとEntity Frameworkを使用する単純なC#コンソールアプリケーションを作成しています(Linux(RHEL)でMonoで実行する意図がありますが、それは他の課題です)。私は.NET 4.0をターゲットにしているので、awaitの代わりに.ContinueWith()を使用しています。GenericWithであいまいな呼び出し

これに加えて、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#で使用したいのかをコンパイラに明示的に知らせる方法はありますか?

答えて

10

はこのように、明示的にラムダパラメータの型を指定してみてください:

.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を指定すると、このあいまい性が解決されます。


コンパイラはAction<Task<TResult>> actionを取るバージョンを仮定することができればそれは確かにいいだろう。多分、他の誰かがそのような行動を取る方法のアイデアを持っているでしょうか?後世のために


...コメントで

あなたはMCattleは彼が唯一の彼のために、ラムダの内部メソッド呼び出しに行方不明括弧に関連するいくつかのコンパイラ風変わりで、この問題に遭遇したことがわかっていることがわかります。一般に、ContinueWithにラムダを渡すときに、Task<TResult>タイプを明示的に指定する必要はありません。

+2

あなたは私を正しい解決に導いてくれました。明示的に '.ContinueWith((タスクt)=> {...})'を宣言すると、次の問題のマスクが解除され、 'Console.WriteLine 'の代わりに' Console.WriteLine(t.Exception.Flatten.ToString) (t.Exception.Flatten()。ToString()) '。これを修正した後、私は明示的なラムダパラメータ宣言を削除することができ、コンパイラは満足していました。 – MCattle

+1

@ MCattle興味深いことに、そこに括弧がないと、コンパイラは2つの過負荷の間で判断できなくなります。私は自分自身で 'ContinueWith'を何度も使用した無数の回数をラムダ入力型に明示的に与えることを覚えていなかったので、私自身の答えは少し不審でした。括弧が足りないことがなぜ違うのか説明できません。 –

+1

使い方によって過負荷が推測され、使用法に構文エラーがある場合、正しい過負荷を推論することができないため、私には意味があります。 – MCattle

関連する問題