2つのクラスで構成されるデータモデルがあり、どちらも同じインターフェイスを実装しているとします。
interface IEntity { }
class EntityTypeA : IEntity { }
class EntityTypeB : IEntity { }
これらのエンティティのリストを含み、それらを使用して何かを行う汎用サービスがあります。サービスには複数の異なる実装があり、すべてIServiceから継承していますが、今のところ「サービス」は1つだけだとしましょう。
interface IService<T> where T : class, IEntity {
// stuff
T GetEntity(Func<T, bool> linq);
}
class Service<T> : IService<T> where T : class, IEntity {
// stuff
IEnumerable<T> _entities;
}
この時点で、さまざまなエンティティ用の新しいサービスを簡単に作成して操作できます。特定のタイプの新しいエンティティをそれらに追加し、メソッドを呼び出し、手動で何もキャストせずにそれらを取り戻します。
IService<EntityTypeA> serviceA = new Service<EntityTypeA>();
IService<EntityTypeB> serviceB = new Service<EntityTypeB>();
すべて問題ありませんが、これらすべてのサービスを1つの場所に保存して、後で必要なサービスをすべて個別の変数に保持しなくても簡単にフェッチできるようにします。
最終的に私はこのようなsthを実行できるようにしたかった:
_manager = new ServiceManager();
_manager.AddService("A", serviceA);
_manager.AddService("B", serviceB);
IService<EntityTypeA> serviceA = _manager.GetService<EntityTypeA>("A");
だから私はこのようなことを試みました:
class ServiceManager {
IDictionary<string, IService<IEntity>> _services;
public void AddService<T>(string key, IService<T> manager) where T : class, IEntity {
_services[key] = (IService<IEntity>)manager;
}
public IService<T> GetService<T>(string key) where T : class, IEntity {
return (IService<T>)_services[key];
}
}
ここでの問題は、「無効なキャスト例外」メソッド(だけでなくとしておそらくのgetService)にaddServiceを呼び出すことで、私はキャストや保存することができないService<EntityTypeA>
にしIService<IEntity>
。EntityTypeAはIEntityを実装し、ServiceはIServiceを実装しているので、これは私にとって少し驚きでした...
だから私の質問は:これらすべての汎用サービスを単一の変数に格納して、マネージャーから1つのメソッドで簡単に取得できるようにするにはどうすればよいですか?このマネージャーをこれらすべてのサービスの管理を担当する単一のインスタンスにしたいのですが、これらすべてのジェネリッククラスを保持する方法がわかりません。
は不変であるため、Service<EntityTypeA>
に格納することはできません。ジェネリック型パラメーターは、特に宣言しない限り、デフォルトでは不変です。一般的には割り当てられません。理由については、この投稿を参照してください。IService<IEntity>
IService
T
Foo<Derived>
Foo<Base>
内容に応じて// stuff
であるIService
、あなたが潜在的に作ることができT
、共変あなたがタイプの値を割り当てることができるように、IService<EntityTypeA>
(したがってService<EntityTypeA>
型の変数に)IService<IEntity>
。
これを行うにはout
、T
:に修飾子を追加します。
interface IService<out T> where T : class, IEntity {
// stuff
T GetEntity(Func<T, bool> linq);
}
これはIService
、T
(とりわけ)を取り込むメソッドがある場合は機能しません。
interface IService<out T> where T : class, IEntity {
// stuff
T GetEntity(Func<T, bool> linq);
void Foo(T t); // compiler error
}
これは型安全性を損なうので:
IService<IEntity> s = new Service<EntityTypeA>();
s.Foo(new EntityTypeB()); // breaks type safety! I can now give Service<EntityTypeA> a EntityTypeB object!
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加