いくつかの派生クラスを持つ抽象クラスがあります
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
...
}
}
それはひどいように見えます。これを行うためのより良い方法は何でしょうか?
はい、Reflectionを使用してください。
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
の新しいインスタンスを直接返すことはありません。
Reflectionまたは System.Activator.CreateInstance を使用して、TypeまたはTypeNameを文字列として基づいてインスタンスを作成できます。
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.");
}
あなたが述べた質問には多くの良い答えがあります。ただし、このタイプの要件にはファクトリパターンを使用することをお勧めします。
'factory'は、静的GetNewMyObject(string pattern)
メソッドとprotected static Dictionary<string, Type>
を基本クラスに追加するのと同じくらい簡単です。次に、派生クラスは、パターン+タイプを(静的コンストラクターで)ファクトリに追加するだけで、基本クラスを変更せずに新しい派生クラスをファクトリに追加できます。
このように、「パターン」文字列はタイプ名と一致する必要はなく、次のように書くことができるように論理パターンマッチングを行う必要もありません。
public static MyObject GetNewMyObject(string pattern)
{
return (MyObject)Activator.CreateInstance(StaticTypeDictionary[pattern]);
}
このようにReflectionを使用して行うことができます...
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-完全修飾クラス名