2016-04-27 10 views
1

私はジェネリックなBaseクラスを持っています。 私は基本クラスを実装する具象クラスを持っています。c#ジェネリックベースクラスの具体的な実装のための工場

さまざまな種類の具象クラスを提供するためのファクトリクラス/メソッドを作成するにはどうすればよいですか?ここで

例:

public class ReceiverBase<T> 
    where T : IInterpreter 
{ ... } 

public class SpecialReceiver : ReceiverBase<OwnInterpreter> { ... } 

public class ReceiverFactory<T> 
    where T : ReceiverBase<IInterpreter>, new() 

    public T Create(string type) { 
     switch(type) { 
      default: 
       return new SpecialReceiver(); 
     } 
    } 
} 

問題はReceiverBaseコンパイラが唯一の制約はなく、インターフェイスとしてクラスを望んでいるので、可能ではないと思われることです。 2番目の問題は、SpecialReceiverをTに変換できないということです。

これを実行する方法はありますか?

=== EDIT:最初の回答に係る実施例を追加しました===

public interface IInterpreter 
{ 
} 

public class OwnInterpreter : IInterpreter 
{ 
    public void Dispose() 
    { 
     throw new NotImplementedException(); 
    } 

    public void DoSomething() { } 
} 



public abstract class ReceiverBase<T> 
    where T : IInterpreter 
{ 
    public T MyReceiver { get; set; } 

    internal abstract void Start(); 
} 

public class SpecialReceiver<T> : ReceiverBase<T> 
    where T : IInterpreter, new() 
{ 
    public void CheckSomething() 
    { 
     MyReceiver.DoSomething(); 
    } 

    internal override void Start() 
    { 
     MyReceiver = new T(); 
    } 
} 

public class ReceiverFactory<T> 
    where T : IInterpreter, new() 
{ 
    public static ReceiverBase<T> Create(string type) 
    { 
     switch (type) 
     { 
      default: 
       return new SpecialReceiver<T>(); 
     } 
    } 
} 

問題は:MyReceiver.DoSomething();動作しないでしょう。 さらに、私はこのような工場を呼び出す必要があります:ReceiverFactory<OwnInterpreter>.Create("");私はそのようにしたいのです:

public class ReceiverBase<T> where T : IInterpreter 
    { 
    } 

    public interface IInterpreter 
    { 
    } 

    public class SpecialReceiver<T> : ReceiverBase<T> 
     where T : IInterpreter 
    { 
    } 

    public class OwnInterpreter : IInterpreter 
    { 
    } 

    public class ReceiverFactory<T> where T : IInterpreter, new() 
    { 
     public ReceiverBase<T> Create(string type) 
     { 
      switch (type) 
      { 
       default: 
        return new SpecialReceiver<T>(); 
      } 
     } 
    } 

あなたがいないだけでできる理由を:ReceiverFactory.Create("SpecialReceiver");

+0

あなたの最初のコメントはまったく真実ではありません。あなたは確かに制約としてインターフェイスを持つことができます。しかし、あなたが経験していることは、制約されている型のインスタンスを '新しくできるようにするために、' new() '制約を含める必要があるということです。 –

+0

コンパイラは言う:タイプIInterpreterはパラメータTとしてそれを使用するためにパブリックなパラメータレスコンストラクタを持っている必要があります。コンパイラはこの行を参照します:T:ReceiverBase 、new() – DARKHalf

+0

OK、私は訂正されました。あなたは制約としてインターフェイスを持つことができますが、この場合は 'new()'を使いたいので、そのコンストラクタが存在することを保証する必要があります。インタフェースはコンストラクタを保証しません。 –

答えて

0

あなたの工場で一般的な方法を使用することができます:あなたが工場を使用しているため

class Program 
{ 
    static void Main(string[] args) 
    { 
     var own = ReceiverFactory.Create<OwnInterpreter>(); 
     var other = ReceiverFactory.Create<OtherInterpreter>(); 
     own.Start(); 
     other.Start(); 
     Console.ReadLine(); 
    } 
} 
interface IInterpreter 
{ 
    void DoSomething(); 
} 

class OwnInterpreter : IInterpreter 
{ 
    public void DoSomething() { Console.WriteLine("Own"); } 
} 

class OtherInterpreter : IInterpreter 
{ 
    public void DoSomething() { Console.WriteLine("Other"); } 
} 

abstract class ReceiverBase<T> where T: IInterpreter, new() 
{ 
    public T Interpreter { get; set; } 
    public ReceiverBase() 
    { 
     Interpreter = new T(); 
    } 
    public void Start() 
    { 
     Interpreter.DoSomething(); 
    } 
} 

class SpecialReceiver : ReceiverBase<OwnInterpreter> { } 
class OtherReceiver : ReceiverBase<OtherInterpreter> { } 

static class ReceiverFactory 
{ 
    private static Dictionary<string, object> factories = new Dictionary<string, object>(); 
    static ReceiverFactory() 
    { 
     RegisterFactory(() => new SpecialReceiver()); 
     RegisterFactory(() => new OtherReceiver()); 
    } 
    public static void RegisterFactory<T>(Func<ReceiverBase<T>> factory) where T : IInterpreter, new() 
    { 
     factories.Add(typeof(T).FullName, factory); 
    } 
    public static ReceiverBase<T> Create<T>() where T : IInterpreter, new() 
    { 
     var type = typeof(T); 
     return ((Func<ReceiverBase<T>>)factories[type.FullName]).Invoke(); 
    } 
} 

実際には、あなたは、ここで「新しい()」制約を必要としません。

+0

いいサンプルをありがとうございますが、ここには一般的な問題があります。私は通訳者を区別するのではなく、レシーバのクラスを区別したいと思います。私の設計上の問題では、私は同じ種類の情報源を持っています。私の場合、これは場所です。 (GPS、Cellなど)あらゆるソースは緯度と経度を提供します。私は今、座標を提供する工場を持っていたい。私はちょうどCreate( "GPS")またはCreate( "Cell")またはこの種の情報を提供するもので工場に電話したいと思う。 – DARKHalf

0

私はあなたがあなたのコードを変更することをお勧めあなたのケースでTを返すのは、SpecialReceiverReceiverBase<IInterpreter>の間の暗黙の変換がないということです。

+0

これは2つの他の問題につながります。 私は、OwnReteriverインスタンスを使用するSpecialReceiverにコードを実装できませんでした。 具体的なIInterpreterで工場に電話する必要があります。この場合はOwnInterpreterになります。ファクトリは、コンフィグレーションまたは他のどこかから読み込むことができる文字列パラメータだけを必要とします。 – DARKHalf

+0

@DARKハーフは何ですか? :) – Kamo

+0

私のオリジナルの質問を編集しました – DARKHalf

0

自分のニーズに合った解決策を見つけることができました。 私は本当に必要なプロパティとメンバーを定義する別のインターフェースIReciverを追加しました。ファクトリメソッドはIReceiverを返すので、ジェネリックのバインディングに関する問題はすべて省略できます。時にはそれは簡単です。 :)

public interface IInterpreter { } 

public interface IReceiver 
{ 
    bool Enabled { get; set; } 
} 

public class OwnInterpreter : IInterpreter 
{ 
    public void DoSomething() { } 
} 

public abstract class ReceiverBase<T> : IReceiver 
    where T : IInterpreter, new() 
{ 
    public T MyReceiver { get; set; } 

    internal abstract void Start(); 

    private bool _isEnabled; 
    public bool Enabled { get { return _isEnabled; } set { _isEnabled = value; OnEnable(value); } } 

    internal abstract void OnEnable(bool isEnabled); 

    protected ReceiverBase() 
    { 
     MyReceiver = new T(); 
    } 
} 

public class SpecialReceiver : ReceiverBase<OwnInterpreter> 
{ 
    public void CheckSomething() 
    { 
     MyReceiver.DoSomething(); 
    } 

    internal override void Start() 
    { 
     // just for testing puropses 
     MyReceiver = new OwnInterpreter(); 
    } 

    internal override void OnEnable(bool isEnabled) 
    { 
     MyReceiver = isEnabled ? new OwnInterpreter() : null; 
    } 
} 

public class ReceiverFactory 
{ 
    public static IReceiver Create(string type) 
    { 
     switch (type) 
     { 
      default: 
       return new SpecialReceiver(); 
     } 
    } 
} 

public class Program 
{ 
    [STAThread] 
    public static void Main() 
    { 
     ReceiverFactory.Create(""); 
    } 
} 
関連する問題