Ideatryout:型付きProviderfactory
-
18-09-2019 - |
質問
私は今、数日間C#.NET(4.0RC)で新しいプロジェクトを開始することを考えてきました。プロジェクトの最終結果は「ProviderFactory」、インターフェース(または抽象クラス)のカップルとデフォルトの「ProviderType」または2を呼んで、今のところ何のIからなるクラスライブラリになります。
すべてのまず、私は.NETで、すでに何と衝突しないように私のクラスの命名を変更することを決定/必要になる場合があります。第二に、それはそのような場合、そのプロジェクトやチュートリアルへの単一のリンクをいただければ幸いですので、私はすでにここに記述していますが、(それも私はそれについて知らなくても、ネイティブ.NET内であるかもしれない)が存在することは良いチャンスです。
私は考えている機能は、単純なプロバイダを私に提供することができますだけで、工場ではありませんが、プロバイダのいずれかの種類を生成することができるはずです。私はこのような何かを書くことができるようにしたい。
BlogProvider bp = ProviderFactory.GetProvider<BlogProvider>();
と存在しない場合は、現在選択されたBlogProviderを返す、またはnullなければなりません。また、私は、例えば
のような一つのタイプのすべての使用可能なプロバイダの上にリストを提供することができるようにしたいですstring[] blogproviders = ProviderFactory.GetRegisteredProviders<BlogProvider>();
とそれが(「ODBCBlogProvider」、「XMLBlogProvider」などのような)ブログプロバイダと文字列の配列を返す必要があります。私はまた、このような場合のために、現在のプロバイダを設定できるようにする必要があります:
ProviderFactory.SetCurrentProvider<BlogProvider>("ODBCBlogProvider");
それは(BlogProvider基本クラスを拡張する必要が原因のもの)ODBCBlogProviderのインスタンスを返す必要があり、私はProviderFactory.GetProvider(呼び出し次回)ように、これは、現在のBlogProvider ODBCBlogProviderを行う必要があります。
また、(あなたが好きな場合はProviderBase)すべてのProviderTypeはProviderTypeName(BlogProvider)とProviderTypeDisplayName(「ブログ」や「ブログプロバイダ」)というProviderTypeに一意であり、そのプロバイダのニーズを拡張し、すべてのプロバイダを持っている必要がありますProviderNameは(ODBCBlogProvider)とProviderDisplayName( "ODBC" または "ODBCブログ" など)を持っています。 ProviderNameはとProviderTypeNameだけで簡単にするためにそこにクラス名が反射することによって得られる可能性があります。
これはおそらく、私は、このような何かをProviderBaseためのインタフェースを必要とするだろうことを意味します:
public interface ProviderBase
{
string ProviderName { get; } // The display-name.
string Description { get; } // A description of the provider type, like "This provides you with a blog."
}
そしてBlogProviderのために、私はこれら二つの部材を実装し、オーバーライドする実際のBlogProvidersためのメソッドを作成する抽象クラスを作成する必要があると思います。
public abstract class BlogProvider : ProviderBase
{
public string ProviderName
{
get { return "Blog"; }
}
public string Description
{
get { return "This provides you with a blog."; }
}
public abstract int GetPostCount();
}
すると、どこかに私のコードで私は
のようなものを実行しなければならなかったと思いますProviderFactory.RegisterProviderType(typeof(BlogProvider));
またはより良いオプションは、このような属性を使用できるようになります:
[Provider("Blog", "This provides you with a blog.")]
public interface BlogProvider
{
int GetPostCount();
}
私はメンバーのどれもが、基本クラスに設定する必要がないので、このアプローチに抽象クラスを使用する必要が表示されません。また、ProviderBaseインタフェースの必要性がなくなっています。 ProviderFactoryがちょうどProviderAttributeを含むすべてのクラス/インタフェースを見つけることができれば、それがその要件だとき、特に、ないODBCBlogProviderだけでBlogProviderを実装する必要があるだろうが、私はこれを行う方法かどうか分からないよりも、理想的な事が原因であろうプロバイダとprovidertypesは両方の外部のアセンブリのために来ることができます。
ProviderFactoryの別の要件は、それは、このように、いくつかの設定ファイル/ストリーム/データベース(そのような何かに設定を保存することができるはずです、ときステートレスな環境で、それが生かされた環境で両方動作するはずということです本当に初期化時からの変更と負荷に)重要ではありませんが、これはオプションでなければなりません。したがって、それはまた、(自分のマシン上でブログを持つことはあまり意味を与えるものではありません)ウェブ上で動作します。
もう一つの要件は、プロバイダは、がの他のプロバイダが機能する必要がある場合がありますということです。例えば、およびAudiEngineだけAudiCarで動作するかもしれません、しかしAudiCarはBmwEngineと完全に実行することができます。
また、(と私はどこ、まだプロバイダクラス自体に多分オプションの属性をそのを入れてよく分からない)、すべてのプロバイダがシングルトンかしないかのオプションを持っている必要があります。
これは、Alでありますlは私が今のところ考えることができます。そこにこれが実装されるべき方法や、天候の任意の入力がすでにそこに実装が大幅に高く評価されるだろうが、私はまだコードを書いていないので、何も変更することができ、これは私が今のところ考えてきたすべてのものです。
解決
まあ、それは(むしろ、過度に派手な名前の)overengineered のIoC / DI のようになります。 >コンテナます。
のIoCのアイデアは、彼ら(コンテナ)は、任意のインターフェイスを実装したり、基本クラスから派生するために、あなたの「協力者」を必要としないことを除いて、ほとんど同じです。
var builder = new ContainerBuilder();
builder.Register<Car>();
builder.Register<Engine>().As<IEngine>();
var container = builder.Build();
// somewhere in the code
var car = container.Resolve<Car>();
これは、DIコンテナの無数の一つである、 autofac に用いた例でありますC#のための/。NETます。
他のヒント
、これはのIoC / DIコンテナに近接しています。ここでも、Autofacを使用して、あなたはこのような何かをやって長い道のりを取得することができます:
var builder = new ContainerBuilder();
builder.Register<Car>();
builder.Register<BmwEngine>();
builder.Register<AudiEngine>();
builder.Register<DefaultEngine>();
builder.Register<EngineSelector>().As<IEngineSelector>().SingletonScope();
builder.Register(
c => {
var selector = c.Resolve<IEngineSelector>();
switch(selector.CurrentEngine)
{
case "bmw":
return c.Resolve<BmwEngine>();
case "audi":
return c.Resolve<AudiEngine>();
default:
return c.Resolve<DefaultEngine>();
}
}
).As<IEngine>().FactoryScoped();
var container = builder.Build();
// somewhere in the code
var selector = container.Resolve<IEngineSelector>();
selector.CurrentEngine = "bmw";
var car = container.Resolve<Car>();