2016-08-19 15 views
0

C#でジェネリックスに少し苦労しています。コードのこの部分を考えてみましょう:一般的な派生型のオブジェクトを返す汎用メソッド

public interface A {}; 
public interface B : A {}; 
public interface C : A {}; 

public interface IMyInterface<in T> where T : A {}; 

public class FirstImpl<T> : IMyInterface<T> where T : B {}; 
public class SecondImpl<T> : IMyInterface<T> where T : C {}; 

は、今私は種類を取り、正しい実装を返すいくつかの工場、する必要があります。

public IMyInterface<T> Create<T>() where T : A 
{ 
    if(typeof(T) is B) { 
     return new FirstImpl<T>(); 
    } 
    if(typeof(T) is C) { 
     return new SecondImpl<T>(); 
    } 
} 

これは2つのレベルでは動作しません。最初のものはリターンタイプです。第2の方法は、より具体的な型が必要なため、第1または第2の実装に "T"を渡すことができないということです。どのようにこれを解決するための任意のアイデア?

+0

「新しいFirstImpl ();」を呼び出すときに、技術的に問題があります。ここでコンパイラは実際にジェネリック型TがBまたはB派生であると納得させることはできません。面白い。思考の糧。 Lemme参照してください。 –

+0

いくつかの 'new'キーワードを削除しましたか?あなたが望むことをしたとしてもコンパイルできないコードを扱わなくても、この質問を理解するのは難しいです。 'return new FirstImpl ();'と 'return new SecondImpl ();'を書きますか? –

+0

今修正されました。 –

答えて

1

デザインをそのまま維持したい場合、最短の方法はCreate<T>()メソッド(public IMyInterface<T> Create<T>() where T : A , B, Cなど)で追加の制約を追加することです。メソッドを完了させるためには、デフォルトのケースの実装が必要になるでしょう。

public IMyInterface<T> Create<T>() where T : A, B, C 
{ 
    if (typeof(T) is B) 
    { 
     return new FirstImpl<T>(); 
    } 
    if (typeof(T) is C) 
    { 
     return new SecondImpl<T>(); 
    } 
    return new DefaultImpl<T>; 
} 
+0

私はこのアプローチを試し、調整しておいてください。アドバイスをありがとう! –

+0

クール!私はここでデザインを同じにしておきたいという前提で答えました。もしあなたがそれを変更することができるのであれば、これ以上のデザインに優しいソリューションが得られるかもしれません。 :) –

+0

実際には2番目の考えでは、これが可能かどうかはわかりません。なぜなら、TはBまたはCだけではなく、両方ではないからです。 –

2

あなたは反射を気にしない場合、あなたはそのように行うことができます:

public static IMyInterface<T> Create<T>() where T : A 
{ 
    if (typeof(B).IsAssignableFrom(typeof(T))) 
    { 
     var type = typeof(FirstImpl<>); 
     var boundType = type.MakeGenericType(typeof(T)); 
     return (IMyInterface<T>) Activator.CreateInstance(boundType); 
    } 
    else if(typeof(C).IsAssignableFrom(typeof(T))) 
    { 
     var type = typeof(SecondImpl<>); 
     var boundType = type.MakeGenericType(typeof(T)); 
     return (IMyInterface<T>) Activator.CreateInstance(boundType); 
    } 

    throw new ArgumentException("unknown type " + typeof(T).Name); 
} 

あなたはジェネリック型を使用して.net fiddle

+0

反射は良いです。私はこれを試してみましょう。 –

+0

var type = typeof(FirstImpl <>)、 "<>"には何が入りますか? –

+0

typeof(FirstImpl <>)は非結合型を表します。私が追加した.net fiddleをチェックすることができます。 – Nico

3

には、コードを持っていつでもそれを試すことができますかそのコードがジェネリック型のパラメータに対して何らかのテストを行っていれば間違ったことになります。 (そして、私は、反射に落とすことはさらに悪いことは言うまでもない)ジェネリックタイプの全体のポイントは、ではないコードをジェネリックタイプに依存するということです。

あなたの例では、より良いアプローチは、このようなものになるだろう:

static IMyInterface<T> CreateB<T>() where T : B 
{ 
    return new FirstImpl<T>(); 
} 

static IMyInterface<T> CreateC<T>() where T : C 
{ 
    return new SecondImpl<T>(); 
} 

すなわち、各シナリオを処理するための異なるメソッドを記述します。呼び出し元は、制約ベースのアプローチがうまくいくかどうか、すでに処理されていることを、とにかく知る必要があります。だから、ちょうど異なるメソッド名を持つことは問題ではなく、それぞれ適切な状況でそれぞれ使用されるべきです。

上記のシナリオが特定のシナリオに対応していない場合は、使用しようとしているジェネリックタイプだけでなく、使用されるコンテキストも示すように質問を改善してください。Minimal, Complete, and Verifiable code example

+0

あなたが言うことは完璧な意味を持っています。私はそれを考えます。コードサンプルの幅広い改善は必要ありません。皆さんが正しいと思っています。 (すべてのタイプは非常に単純です...私は実験的なフレームワークを作成しています。私たちは実験のための超柔軟性を求めています。なぜなら、すべてをパラメータ化しようとしているからです。) –

関連する問題