2012-03-08 23 views
5

私はちょうどこれを使用しようとしていたので、それは部分的な好奇心と一部です。次の定義がある場合は、メンバーが既に定義されているため、コンパイラーはこれを許可しません。ジェネリック型パラメータの排他的なオーバーロードを許さない理由は何ですか?ジェネリック型パラメータのオーバーロードが許可されていませんか?

void Get<T>() where T: struct {} 
void Get<T>() where T: class {} 

これには固有の問題はないようです。定義が重複する場合にコンパイラが選択する必要があるとは必ずしも明確ではないと主張するかもしれない(しかし、一般的な解決法が最初に最も一致すると思われる)。

誰かがこれを否認している理由についてリソースを理解しているか指摘するのに役立つことがありますか?

+0

あなたの実際のユースケースはどのようなことでしたか? – AakashM

+0

@AakashM:単純ですが、nullable型以外の値型とは異なる方法でnullable型を変換する必要がありました。私は一般的な過負荷がそれを直す簡単な方法だと思った。メソッドはオブジェクトと型paramを取ります。型のparamを制限することはできません(まあ、できますが、それをオーバーロードできません)。 – Abel

答えて

9

エリックリペットはすでに一般的な制約やメソッドのシグネチャのブログ記事では、このいずれかを答え:一般的なタイプのhttp://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

制約ゆえあなたがその2つのメソッドを持つことができない、CLRでメソッドのシグネチャの一部ではありませんジェネリック型の制約のみが異なります。 CLRサポートがなければ、C#に他の.NET言語と互換性のある賢明な方法でこれらをサポートさせることは非常に面倒です。

+0

そのように述べると、それは論理的なようです。 1つは、それがメソッドシグネチャの一部になっていないのは不思議ではないでしょうか? Anders Hejlsbergはそれを他の方法で設計しないのに十分な理由がありましたか? Lippertの記事をまだ完全に読まなかった。ポインタありがとう。 – Abel

+1

私の推測では、それはCLRの制限だということです.CLRでは、メソッドシグネチャのジェネリック型の制約も考慮されません。メソッドシグニチャのバイナリ表現にジェネリック制約を表す方法はないので、かなり深い制限です。 – thecoop

+4

@Abel:thecoopは正しいです。これはCLRの制限です。もちろん、理論的には制約を署名の一部にすることもできますが、これは確かに特定のケースで役立ちます。しかし、一般的なケースでは、多くの問題があります。例: 'void M ()ここで、T:IFoo {}'と 'void M ()はT:IBar {}'とは異なるメソッドシグネチャです。どのメソッドが 'M 'で、 'Blah'は' IFoo'と 'IBar'の両方を実装するクラスですか?あいまいな署名を処理するための規則は既に十分複雑です。曖昧になるような全く新しい方法を追加しないでください。 –

1

structの制約はNullable<T>ですが、本当に不幸です。 Nullable<String>Nullable<Nullable<Nullable<int>>>のようなものは無駄かもしれませんが、何ですか?前者をその内容として囲みます。内容としてコンテンツをunboxし、コンテンツがnullでない場合はHasValueを設定します。すべてのnullableがHasValueと報告した場合は、前者をintとし、アンボックスの場合は、コンテンツがnullでない場合はすべてのネストされたアイテムをHasValueと設定します。

それ以外の場合は、Tをパラメータとして受け入れるデリゲートプロパティを含む型パラメータTを持つ静的汎用クラスを作成することをお勧めします。プロパティは、Tの型をチェックし、デリゲートをstructまたはclassのいずれかのバージョンに適切に設定するメソッドを指すように初期化する必要があるプライベートフィールドの内容を返します。

ここに私が話していることの例があります。これは、構造体/クラスの制約ではなく、さまざまなインタフェースの制約を使用しますが、同じ原理を効果的に使用することができます。

 
     static class _FooDispatcher<T> 
     { 
      public static Action<T> Foo = setupFoo; 

      static void doFooWithIGoodFoo<TT>(TT param) where TT : IGoodFoo 
      { 
       Console.WriteLine("Dispatching as IGoodFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference"); 
       param.Foo(); 
      } 
      static void doFooWithIOkayFoo<TT>(TT param) where TT : IOkayFoo 
      { 
       Console.WriteLine("Dispatching as IOkayFoo with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference"); 
       param.Foo(); 
      } 
      static void doFooSomehow<TT>(TT param) 
      { 
       Console.WriteLine("Nothing exciting with {1} type {0}", typeof(TT).ToString(), typeof(TT).IsValueType ? "value" : "reference"); 
      } 
      static void setupFoo(T param) 
      { 
       System.Reflection.MethodInfo mi; 
       if (typeof(IGoodFoo).IsAssignableFrom(typeof(T))) 
        mi = typeof(_FooDispatcher<T>).GetMethod("doFooWithIGoodFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
       else if (typeof(IOkayFoo).IsAssignableFrom(typeof(T))) 
        mi = typeof(_FooDispatcher<T>).GetMethod("doFooWithIOkayFoo", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
       else 
        mi = typeof(_FooDispatcher<T>).GetMethod("doFooSomehow", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
       Foo = (Action<T>)(@Delegate.CreateDelegate(typeof(Action<T>), mi.MakeGenericMethod(typeof(T)))); 
       Foo(param); 
      } 
     } 
関連する問題