22

いくつかの派生クラスを持つ抽象クラスがあります

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 句がたくさんあることです。

public MyObject Create(string pattern)
{
    MyObjectA obj = new MyObjectA();
    if(obj.IsObject(pattern)
    {
        return obj;
    }
    else
    {
        MyObjectB objb = new MyObjectB();
        if(objb.IsObject(pattern);
            return objb;
        else
            ...
    }
}

それはひどく見えます。これを行うためのより良い方法は何でしょうか?

4

5 に答える 5

29

はい、リフレクションを使用します。

Type.GetTypeを使用Typeして、クラスのインスタンスを文字列で取得しActivator.CreateInstance、次のように を使用してインスタンス化できます。

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

オーバーロードも使用できますActivator.CreateInstance(string, string)が、これは必須の新しいインスタンスを直接返すことはありませんType

于 2012-12-19T12:08:12.457 に答える
7

Reflection またはSystem.Activator.CreateInstanceを使用して、文字列としての Type または TypeName に基づいてインスタンスを作成できます。

于 2012-12-19T12:07:34.530 に答える
5

Rudi Visser が言ったように、リフレクションを使用する必要があります。

また、クラス名を取得するには、ハードコーディングしないでください。name プロパティを使用する場合は、次のように記述します

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

クラスの名前がない場合は、それを表す文字列だけで、派生したすべてのクラスをチェックできます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.");
}
于 2012-12-19T12:15:27.560 に答える
1

あなたが述べた質問には多くの良い答えがあります。ただし、このタイプの要件にはファクトリ パターンを使用することをお勧めします。

あなたの「工場」は、静的GetNewMyObject(string pattern)メソッドを基本クラスに追加するだけでなく、protected static Dictionary<string, Type>. その後、派生クラスはパターンと型をファクトリに (静的コンストラクターで) 追加するだけで、基本クラスを変更せずに新しい派生クラスをファクトリーに追加できます。

このようにして、「パターン」文字列は型名と一致する必要がなく、次のように論理パターン マッチングを行う必要もありません。

public static MyObject GetNewMyObject(string pattern)
{
  return (MyObject)Activator.CreateInstance(StaticTypeDictionary[pattern]);
}
于 2012-12-19T22:01:04.707 に答える
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 - 完全修飾クラス名

于 2012-12-19T12:32:14.423 に答える