2012-12-19 4 views
21

によってクラスを返します私はいくつかの派生クラスで抽象クラスを持つ文字列値

public abstract class MyObject 
{ 
    public string name { get; set; } 
    public bool IsObject(string pattern); 
    ... 
} 

public class MyObjectA : MyObject 
{ 
    public string name { get { return "MyObjectA"; } set; } 
    public bool IsObject(string pattern) { ... } 
    ... 
} 

public class MyObjectB: MyObject 
{ 
    public string name { get { return "MyObjectB"; } set; } 
    public bool IsObject(string pattern) { ... } 
    ... 
} 

今、私は、文字列に基づいて(MyObjectA/MyObectB)私の特定のクラスを返す関数を、持っていると思います。問題は、それを得るためにif/else節がたくさんあることです。

これはちょっとひどいです。これを行うより良い方法は何でしょうか?

答えて

28

はい、反射を使用します。

あなたはこのような何か、そして Activator.CreateInstanceを使用して、それをインスタンス化し、文字列でクラスの Typeのインスタンスを取得するために Type.GetTypeを使用することができます

:またActivator.CreateInstance(string, string)オーバーロードを使用することができますが、これは直接ではなく、希望

public MyObject Create(string pattern) 
{ 
    Type t = Type.GetType(pattern); 
    if (t == null) { 
     throw new Exception("Type " + pattern + " not found."); 
    } 
    return Activator.CreateInstance(t); 
} 

Typeの新しいインスタンスを返す必要があります。

5

Rudi Visser氏によれば、reflectionを使用する必要があります。

また、クラス名を取得するには、ハードコードしないでください。あなたの名前プロパティを使用するwhant場合は、それを表現するクラスの名前、ちょうどいくつかの文字列を持っていない場合 ちょうどあなたがMyObject

public MyObject Create(string pattern) 
{ 
    Type[] types = Assembly.GetExecutingAssembly().GetTypes(); 
    foreach (Type type in types.Where(t => t.IsSubclassOf(typeof(MyObject)))) 
    { 
     MyObject obj = (MyObject)Activator.CreateInstance(type); 
     if (obj.name == pattern) 
     { 
      return obj; 
     } 
    } 
    throw new Exception("Type " + pattern + " not found."); 
} 
から派生したすべてのクラスをチェックできるより、

public abstract class MyObject 
{ 
    public string name 
    { 
     get 
     { 
      return this.GetType().Name; 
     } 
    } 
    public bool IsObject(string pattern); 
    ... 
} 

を書きます

+0

+1グッドコール。明示的に 'set'を削除することも有効です。 –

+0

これは単なる例です。名前の文字列はクラスの名前と正確には一致しません。しかし、私はそれをそれに変換することができます。 – Link

0

それはこのようにリフレクションを使用して...

public object getInstance(string assemblyName, string className, object[] constructorParameters) 
    { 
     System.Reflection.Assembly asm = System.Reflection.Assembly.Load(assemblyName); 
     return asm.CreateInstance(className, false, System.Reflection.BindingFlags.CreateInstance, null, constructorParameters, null, null); 
    } 

のAssemblyName行うことができます - フルパス+アセンブリ名

className - 完全修飾クラス名

1

あなたの記載された質問には多くの良い回答があります。しかし、このタイプの要件には工場パターンを使用することを提案します。

「ファクトリー」は、GetNewMyObject(string pattern)メソッドを基本クラスに追加するだけで簡単です(protected static Dictionary<string, Type>)。次に、派生クラスはパターン+型をファクトリに静的コンストラクタで追加するだけで、新しい派生クラスをベースクラスを変更せずにファクトリに追加することができます。

この方法は、あなたの「パターン」文字列は、タイプ名と一致する必要はありませんし、また、あなたが書くことができ、任意の論理的なパターンマッチングを行う必要はありません。

public static MyObject GetNewMyObject(string pattern) 
{ 
    return (MyObject)Activator.CreateInstance(StaticTypeDictionary[pattern]); 
} 
関連する問題