2009-05-12 7 views
17

私は、タイプのセットで使用することを意図したラッパー汎用クラスを持っています。これらの型はユーティリティによって生成され、すべて基本クラスのClientBaseから派生します。 ClientBaseにはデフォルトのコンストラクタしかありませんが、生成されるすべての型はデフォルトコンストラクタを持ち、コンストラクタはパラメータとして文字列を取ります。ラッパークラスのコンストラクターでは、文字列を受け取るコンストラクターを使用して型のインスタンスをインスタンス化します。ジェネリック型を制約するには、特定のパラメータを取るconstrutorが必要ですか?

public class ClientBase 
{ } 

public class GenericProxy<T> 
    where T: ClientBase, new() 
{ 
    T _proxy; 

    public GenericProxy(string configName) 
    { 
     _proxy = new T(configName);  
    } 
} 

このコードはコンパイルされません。タイプTは、文字列を取るコンストラクタを持つことが保証されていないためです。型Tに文字列を取るコンストラクタが必要であることを強制するジェネリッククラスの制約を定義する方法はありますか?これが不可能な場合、このような状況を処理するための良い選択肢は何ですか?

答えて

24

それは不可能です。

  • は別の指定
  • T
  • のための工場として機能するようにデリゲートを指定します。私は

    代替...これを処理するために"static interfaces"を見てみたいと思いますが、それらをいつでもすぐに期待していません初期化のためのT自体のインターフェイスを指定(およびTインターフェイスを実装するように制約を追加)T

  • ための工場として作用する界面

のTh最初の2つは本当に同等です。基本的に、あなたはこのような何かにプロキシクラスを変更したい:

public class GenericProxy<T> 
    where T: ClientBase, new() 
{ 
    string _configName; 
    T _proxy; 
    Func<string, T> _factory; 

    public GenericProxy(Func<string, T> factory, string configName) 
    { 
     _configName = configName; 
     _factory = factory; 
     RefreshProxy(); 
    } 

    void RefreshProxy() // As an example; suppose we need to do this later too 
    { 
     _proxy = _factory(_configName); 
    } 
} 

を(私はあなたが後でそれ以上のインスタンスを作成したいとしていると仮定 - それ以外の場合はあなたにもコンストラクタにTのインスタンスを渡すかもしれません。)

1

Jonノートでは、このための組み込みサポートはありませんが、控えめに、Expressionを使用してコンストラクタへの型指定された代理人(リフレクションよりも高速)を作成できます。これを行うコードはMiscUtilMiscUtil.Linq.Extensions.TypeExt)にあります。

1

これは、メソッドを制約する、あなたの実際の質問に答えるが、完全を期すために、ここであなたはリフレクションを使用して、実行時に求めているものを行うことができる方法ですされていません。ここで

private T Get<T>(string id) 
    { 
    var constructor = typeof(T).GetConstructor(new Type[] { typeof(X), typeof(Y) }); 
    if (constructor == null) throw new InvalidOperationException("The type submitted, " + typeof(T).Name + ", does not support the expected constructor (X, Y)."); 

    var data = GetData(id); 
    return (T)constructor.Invoke(new object[] { data.x, data.y }); 
    } 
0

はベースの完全な実施例であります@JonSkeetの答えに:ice cream

using System; 
using System.Collections.Generic; 

namespace GenericProxy 
{ 
    class Program 
    { 
     static void Main() 
     { 
      GenericProxy<ClientBase> proxy = new GenericProxy<ClientBase>(ClientBase.Factory, "cream"); 

      Console.WriteLine(proxy.Proxy.ConfigName); // test to see it working 
     } 
    } 

    public class ClientBase 
    { 
     static public ClientBase Factory(string configName) 
     { 
      return new ClientBase(configName); 
     } 

     // default constructor as required by new() constraint 
     public ClientBase() { } 

     // constructor that takes arguments 
     public ClientBase(string configName) { _configName = configName; } 

     // simple method to demonstrate working example 
     public string ConfigName 
     { 
      get { return "ice " + _configName; } 
     } 

     private string _configName; 
    } 

    public class GenericProxy<T> 
     where T : ClientBase, new() 
    { 
     public GenericProxy(Func<string, T> factory, string configName) 
     { 
      Proxy = factory(configName); 
     } 

     public T Proxy { get; private set; } 
    } 
} 

次の出力を見ることが期待

関連する問題