派生クラスを作成する静的ファクトリ メソッドを持つ基本クラスがあります。
public class Fruit
{
...
static Dictionary<string, Type> classes = new Dictionary<string, Type>
{
{"apple", typeof(Apple)}
,{"orange", typeof(Orange)}
}
public static Fruit makeFruit(string typeName) {
if(classes[typeName] == null) throw new Exception("invalid fruit type");
Fruit fruit = Activator.CreateInstance(classes[typeName]) as Fruit;
// do some intializations
return fruit;
}
}
Fruit クラスのコード自体を変更せずに、Fruit から派生したクラスを追加し、Fruit クラスにそれを知らせるにはどうすればよいですか? 実際には、Banana.DLL をドロップするか、Banana.cs ファイルをプロジェクトに追加するだけで、フルーツを追加できる必要があります。JavaScript のような他の言語では、クラス宣言の直後にクラスを Fruit の静的配列に追加するだけです。
function Banana()
{
...
}
Fruit.classes['banana'] = Banana;
もちろん、これは C# では不可能です。コードを静的コンストラクター内に配置しようとしましたが、ctor はクラスの最初のインスタンス化の前にのみ呼び出されるため、それも機能しません。心に浮かぶもう 1 つの回避策は、すべてのアセンブリで定義されているすべてのクラスを基底クラスでスキャンして、すべての派生クラスを見つけ、各派生クラスで定義されている静的文字列メンバーから typeName を取得することですが、それはやり過ぎのように感じます。何を指示してるんですか?
Gupta が MEF を使用するよう提案した後、私が現在行っていることは次のとおりです。
次のような果物情報クラスを追加しました。
abstract class FruitInfo
{
readonly Type type;
readonly string typeName;
public FruitInfo(Type type, string typeName)
{
this.type = type;
this.typeName = typeName;
}
}
Fruit ごとに FruitInfo クラスを作成します。
class Banana : Fruit
{
...
}
[Export(typeof(FruitInfo))]
class BananaInfo : FruitInfo
{
public BananaInfo() : base(typeof(Banana), "banana") { }
};
Fruit でこの静的関数を使用して型をインポートします。
public static void importAllFruitTypes()
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
IEnumerable<FruitInfo> fruitInfos = container.GetExportedValues<FruitInfo>();
foreach(FruitInfo fruitInfo in fruitInfos) {
class[fruitInfo.typename] = fruitInfo.type;
}
}
これを改善するための提案は大歓迎です。