web-dev-qa-db-ja.com

クラス名だけを知っているオブジェクトを作成しますか?

私はクラスのセットを持っています、それぞれが異なるです 戦略 同じ仕事をするために。

namespace BigCorp.SuperApp
{
    public class BaseClass { }
    public class ClassA : BaseClass { }
    public class ClassB : BaseClass { }
}

使用する戦略の選択は構成可能です。 app.configファイルでフルタイプ名「BigCorp.SuperApp.ClassB」ではなくクラス名「ClassB」のみを構成したい。

<appConfig>
   <SuperAppConfig>
      <Handler name="ClassB" />
   </SuperAppConfig>
</appConfig>

ただし、リフレクション呼び出しは、特に完全な型名を期待しているため失敗します

Type t = Type.GetType("ClassB"); // results in t == null
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails

クラス名のみを構成しているときにこれを機能させるにはどうすればよいですか?名前空間を完全な型名のクラス名に連結しますか?動作する別のリフレクションコールはありますか?

これが役に立たないと思われ、構成に完全な型名が含まれていることを期待する必要がある場合は、その解決策を受け入れます。私を説得する根拠を提供してください。

(このアセンブリ/名前空間の外部から型をロードしません)

15

すべてのクラスが同じ名前空間から取得されることがわかっているので、一度構成して次のように使用します。

<appConfig>
   <SuperAppConfig handlerNamespace="BigCorp.SuperApp">
      <Handler class="ClassB" />
   </SuperAppConfig>
</appConfig>

編集:nameclassに変更しましたその属性の意味をより適切に示すため。

6
Bryan Watts

Assembly-qualified-nameを使用するか、Assemblyを取得してAssembly.GetType(name)を使用します。この場合、構成ファイルに型が必要なので、Assembly-qualifiedが有効な方法ですが、すべての型が同じアセンブリにあることがわかっているため、次のようになります。

_Assembly assembly = typeof(SomeKnownType).Assembly; // in the same Assembly!
Type type = Assembly.GetType(name); // full name - i.e. with namespace (perhaps concatenate)
object obj = Activator.CreateInstance(type);
_

静的Type.GetType(string)には、混乱を引き起こすことが多いプロービングルールがあります...呼び出し元のアセンブリといくつかのシステムアセンブリを調べますが、すべてのロードされたアセンブリを調べます。

18
Marc Gravell
(このアセンブリ/名前空間の外部から型をロードしません)

上記の行があるため、名前空間が何であるかを知っていると想定しても安全です。あなたは次のようなことをすることができませんでした:

Type t = Type.GetType("Namespace." + className); 
BaseClass c = Activator.CreateInstance(t) as BaseClass; 

おそらく追加のアセンブリを介して、将来ロードされる追加の戦略クラスを追加できる可能性があると予想される場合は、クラス名を完全修飾する必要があります。とにかくこれをお勧めします。アプリケーションの拡張性を強化できるからです。

5
Kyle Trauberman

アプリケーション構成では完全なタイプ名を使用します。以下はもう少し完全ですが、それでも些細な例です

<SuperAppConfig>
   <ObjectConfig provider="BigCorp.SuperApp.ClassA">
      <add name="one" />
      <add name="two" />
   </ObjectConfig>
</SuperAppConfig>

そして実際にこれを作成するファクトリクラス

private static Assembly a = typeof(IFactoryObject).Assembly;
public static IFactoryObject CreateObject(String providerName)
{
    Type t = a.GetType(providerName)
    IFactoryObject o = Activator.CreateInstance(t) as IFactoryObject;
    return o;
}
2
BaseClass c = Activator.CreateInstance(t) as BaseClass; // fails

CreateInstanceは、ObjectHandleにラップされたBaseClassのインスタンスではなく、BaseClassのインスタンスを返さないという事実からも生じる可能性があります。

UnWrapメソッドを使用した後、BaseClassにキャストします。

1
citronas