私はいくつかの例で私の問題を説明すると思います..
interface IModel {}
class MyModel : IModel {}
interface IRepo<T> where T: IModel {
}
class Repo : IRepo<MyModel> {
}
// Cannot implicitly convert.. An explicit convertion exists. Missing cast?
IRepo<IModel> repo = new Repo();
だから私は共分散が必要です..
interface IRepo<out T> where T: IModel {
}
いいですね、うまくいきます。それから私はそれを使いたい:
interface IRepo<out T> where T: IModel {
T ReturnSomething();
}
class Repo : IRepo<MyModel> {
public MyModel ReturnSomething() { return default(MyModel); }
}
すべて問題ありませんが、リポジトリにもオブジェクトを挿入する必要があります。out パラメータでは、これを行うことはできません。
// Invalid variance: The type parameter 'T' must be contravariantly valid on 'IRepo<T>.InsertSomething(T)'. 'T' is covariant.
interface IRepo<out T> where T: IModel {
T ReturnSomething();
void InsertSomething(T thing);
}
class Repo : IRepo<MyModel> {
public MyModel ReturnSomething() { return default(MyModel); }
public void InsertSomething(MyModel thing) { }
}
だから私は2つのパラメータを追加しようとします:
interface IRepo<out TReturn, TInsert>
where TReturn : IModel
where TInsert : IModel
{
TReturn ReturnSomething();
void InsertSomething(TInsert thing);
}
そして、最初の例と同じエラーが発生します。使用時に同じエラーが発生しますin TInsert
では、一体どうすれば挿入とフェッチの両方をサポートできるのでしょうか?
編集:だから私は可能な解決策を見つけましたが、それは最適とはほど遠いです
interface IRepo<out TResult> where TResult : IModel {
TResult ReturnSomething();
// I need to duplicate my constraint here..
void InsertSomething<TInsert>(TInsert thing) where TInsert : IModel;
}
class Repo : IRepo<MyModel> {
public MyModel ReturnSomething() { return default(MyModel); }
// ... And here
public void InsertSomething<T>(T thing) where T: IModel { }
}
EDIT2 : エリックに応えて: これは、私が達成しようとしていることのより完全な例です。IRepo インスタンスをグループ化できるように共分散が本当に必要ですが、モデルをインスタンスとして使用して追加/更新メソッドを持たせたいと思っています。アイテムを追加するためのコンパイル時のタイプ セーフを取得できないことは理解していますが、このユース ケースでは要素を読み取るだけで済みます。
interface IModel { }
class SomeModel : IModel { }
class OtherModel : IModel { }
interface IRepo<T>
{
T ReturnSomething();
void AddSomething(T thing);
}
interface ISubRepo<T> : IRepo<T> where T : IModel { }
class SomeSubRepo : ISubRepo<SomeModel> {
public SomeModel ReturnSomething() { return default(SomeModel); }
public void AddSomething(SomeModel thing) { }
}
class OtherSubRepo : ISubRepo<OtherModel> {
public OtherModel ReturnSomething() { return default(OtherModel); }
public void AddSomething(OtherModel thing) { }
}
class Program {
static void Main(string[] args)
{
ISubRepo<IModel>[] everyone = new ISubRepo<IModel>[] {
new SomeSubRepo(),
new OtherSubRepo()
};
WorkOnAll(everyone);
}
static void WorkOnAll(IEnumerable<ISubRepo<IModel>> everyone)
{
foreach(ISubRepo<IModel> repo in everyone) {
IModel model = repo.ReturnSomething();
// Etc.
}
}
}