2012-11-13 6 views
12

.NET 4を使用すると、コンパイラが以下のサンプルの最初のメソッド呼び出しを解決できないことが混乱しています。デフォルトのパラメータとジェネリックでのメソッド解決の問題

using System; 

namespace MethodResolutionTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      NonGeneric foo = null; 

      // ambiguous 
      foo.Ext1(x => new NonGeneric()); 

      // resolves to first Ext1 
      foo.Ext1(x => new NonGeneric(), 1); 


      // resolves to first Ext2 
      foo.Ext2(x => new NonGeneric()); 

      // resolves to first Ext2 
      foo.Ext2(x => new NonGeneric(), 1); 

      // resolves to second Ext2 
      foo.Ext2(x => "foo"); 

      // resolves to second Ext2 
      foo.Ext2(x => "foo", 1); 


      // resolves to first Ext3 
      foo.Ext3(x => new NonGeneric()); 

      // resolves to first Ext3 
      foo.Ext3(x => new NonGeneric(), 1); 

      // resolves to second Ext3 
      foo.Ext3(x => "foo"); 

      // resolves to second Ext3 
      foo.Ext3(x => "foo", 1); 
     } 
    } 

    public class NonGeneric 
    { 
    } 

    public class Generic<T> : NonGeneric 
    { 
    } 

    public static class Extensions1 
    { 
     public static NonGeneric Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0) 
     { 
      return null; 
     } 

     public static Generic<TNext> Ext1<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0, string s = null) 
     { 
      return null; 
     } 
    } 

    // only difference between Extensions2 and Extensions1 is that the second overload no longer has a default string parameter 
    public static class Extensions2 
    { 
     public static NonGeneric Ext2(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0) 
     { 
      return null; 
     } 

     public static Generic<TNext> Ext2<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0) 
     { 
      return null; 
     } 
    } 

    // Extensions3 explicitly defines an overload that does not default the int parameter 
    public static class Extensions3 
    { 
     public static NonGeneric Ext3(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext) 
     { 
      return Ext3(first, getNext, default(int)); 
     } 

     public static NonGeneric Ext3(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0) 
     { 
      return null; 
     } 

     public static Generic<TNext> Ext3<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0) 
     { 
      return null; 
     } 
    } 
} 

誰もがこれにいくつかの光を当てることができますか?コンパイラの助けになるようにAPIを変更する以外の方法はありませんが(上記のExtensions3)、もっと簡単で良い方法があれば、それを聞いてみたいと思います。

答えて

1

2番目のExt1拡張メソッドに2つのオプションのパラメータがあるため、あいまいです。最初の呼び出しでは両方のパラメーターが省略されているため、コンパイラーはどちらを使用するかを知りません。 C# 4.0 Language Specificationから

§7.5.3オーバーロードの解決:

該当する候補関数メンバーのセットを考えると、そのセットで最高の機能部材が配置されています。セットに1つの関数メンバーのみが含まれている場合、その関数メンバーは最適な関数メンバーです。さもなければ、各関数メンバが§7.5.3.2の規則を使用する他のすべての関数メンバと比較されるならば、最良の関数メンバは与えられた引数リストに関して他のすべてのメンバよりも優れている1つの関数メンバです。他のすべての関数メンバーよりも優れた関数メンバーが正確に1つもない場合、関数メンバーの呼び出しはあいまいであり、バインディング時エラーが発生します。さらに、より良い機能のメンバー§7.5.3.2

:なし対応する引数と

オプションのパラメータは、これが何を意味するのか、パラメータリスト

から削除され、そのときでありますメソッド呼び出しの最後の2つの引数を省略し、NonGeneric型が推論されている(§7.5.2の型推論を参照)、両方のメソッドは次のようになります。

Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext) 

このように、彼らはあいまいになる...

私は§7.5.3.2またはさらなる情報のための仕様であっても全体§7.5.3を読んで推薦します。

ソリューションは、あなたのメソッドの宣言を変更したり、完全に最初のオーバーロードを削除し、二を聞かせてのいずれかにある、それはないですので、仕事:)

+0

は、コンパイラは、 'Extensions2'と' Extensions3'シナリオの両方で正常に選択しますそれは簡単です。また、もし私がデフォルトの 'int'パラメータを必要としないなら、私は明らかにそれを最初に宣言しませんでした! –

+0

しかし、オプションのパラメータを持つ2つの方法があるのはなぜですか?オプションのパラメータを省略すると、あいまいさがありますか?絶対に**両方の方法が必要な場合は、あなたの 'Extensions2'または' Extensions3'のいずれかのソリューションを使う必要があります。 – khellang

+0

@khellang:C#言語仕様のセクションで、このような動作(オーバーロードの解決のあいまいさ)につながることがありますか? –

関連する問題