2016-05-06 5 views
2

クラス内のジェネリックフィールドをコンストラクタ内の特定のタイプに特化する方法はありますか?例えばクラスのジェネリックフィールドのインスタンス化

class concreteClass1 
{ 
    private int a; 
    public concreteClass1(int a) 
    { 
     this.a = a; 
    } 
} 

class concreteClass2 
{ 
    string b; 
    public concreteClass2(string b) 
    { 
     this.b = b; 
    } 
} 

class A<T> 
{ 
    private T field; 
    public A(int x) 
    { 
     field = new concreteClass1(x); //error here CS0029 
    } 

    public A(string y) 
    { 
     field = new concreteClass2(y); //error here CS0029 
    } 
} 

のでTconcreteClass1またはconcreteClass1のいずれであってもよく、それぞれのctorsが異なるシグネチャを持つことになります。

+2

誰かが「new A (42);」と書くときに何をしたいですか? – Servy

+0

それから、 'A'は私が読み書きできる' concreteClass1'フィールドを持っています。 @Servy – shinzou

+3

これは[XY問題](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)のようです。何をしようとしているのですか?これを行う必要がありますか? – juharr

答えて

1

私は、依存性注入を使用するには、このリファクタリングでしょう。そのようにして、クラスには、それに依存する他のクラスを作成するためのコード(例えば、myConcreteField = new ConcreteA<T>(4);)が含まれていません。依存性注入は、コードがこのような困難な結び目に結びつくのを防ぐために使用されます。

(あなたの例は非常に抽象的なので、少し難しいです。「コンクリート」や「実装」などのクラス名を使用すると、コンセプトを記述するために同じ単語を使用するため、 。

class Implementation<T> 
{ 
    private readonly ISomethingThatTheOtherClassNeeds<T> _something; 

    public Implementation(ISomethingThatTheOtherClassNeeds<T> something) 
    { 
     _something = something; 
    } 

    void DoSomething() 
    { 
     Console.Write(_something.MySomething.ToString()); 
    } 
} 
:)

代わりに、そのConcreteものが何であれ、あなたのImplementationクラスで次に

public interface ISomethingThatTheOtherClassNeeds<T> 
{ 
    public int MySomething {get;set;} 
} 

public class SomethingThatTheOtherClassNeeds : ISomethingThatTheOtherClassNeeds<string> 
{ 
    public int MySomething {get;set;} 
} 

のように、インターフェイスを宣言

違いは、そのクラスが何であれ作成するのではなく、コンストラクタのImplementationに渡されている点です。 Implementationは、クラスが何であるかを知らず、インターフェイスにマッチすることだけを知っています。

これは、他のクラスがより多くのクラスに依存する場合に特に役立ちます。あなたのクラスでnewを呼び出すことによってそれらを作成する場合、そのクラスはそのクラスの作成方法を知っている必要があります。

次に、Windsor、Unity、Autofacなどの依存性注入コンテナを使用すると、それをワイヤリングすることができます。これはコンソールアプリケーションではあまり一般的ではありませんが、私はこれが実際よりも実験的であると推測しています。

1

これは、タイプを変換する必要があるため、ややこしいものでした。多分これはあなたのために働くでしょうか?

class Program 
{ 
    static void Main(string[] args) 
    { 
     var myImplementation = new Implementation<int>(4); 
     var myImplementation2 = new Implementation<string>("Hello World"); 

     Console.WriteLine(myImplementation.myConcreteField); // outputs 4! 
     Console.WriteLine(myImplementation2.myConcreteField); // outputs Hello World 
    } 
} 

abstract class MyAbstract<T> 
{ 
    public T MySomething; 
    public MyAbstract(T something) 
    { 
     MySomething = something; 
    } 
} 

class ConcreteA<T> : MyAbstract<T> 
{ 
    public ConcreteA(int something) : base((T)Convert.ChangeType(something, typeof(T))) 
    { 
    } 
} 

class ConcreteB<T> : MyAbstract<T> 
{ 
    public ConcreteB(string something) : base((T)Convert.ChangeType(something, typeof(T))) 
    { 
    } 
} 

class Implementation<T> 
{ 
    public MyAbstract<T> myConcreteField; 

    public Implementation(T a) 
    { 
     myConcreteField = new ConcreteA<T>(4); 
    } 

    void DoSomething() 
    { 
     Console.Write(myConcreteField.MySomething.ToString()); 
    } 
} 
+1

これはジェネリック型の引数の代わりに 'object'を使うよりもどのように優れていますか?クラスをジェネリッククラスとして使用していない場合は、汎用クラスにしないでください。 – Luaan

+0

@LuaanよくmyConcreteFieldは、正しい型にキャストされています。それ以外は、私が思う理由はない。 – Gaspa79

関連する問題