オブジェクトを汎用インターフェイスにキャストする
質問
次のインターフェースがあります:
internal interface IRelativeTo<T> where T : IObject
{
T getRelativeTo();
void setRelativeTo(T relativeTo);
}
と、それを実装する(すべき)クラスの束。例:
public class AdminRateShift : IObject, IRelativeTo<AdminRateShift>
{
AdminRateShift getRelativeTo();
void setRelativeTo(AdminRateShift shift);
}
これら3つは同じではないことに気付きました:
IRelativeTo<>
IRelativeTo<AdminRateShift>
IRelativeTo<IObject>
しかし、それにもかかわらず、すべてIRelativeToを実装するAdminRateShift(およびFXRateShift、DetRateShift)などのすべての異なるクラスを操作する方法が必要です。 AdminRateShiftをオブジェクトとして返す関数があるとします:
IRelativeTo<IObject> = getObjectThatImplementsRelativeTo(); // returns Object
インターフェイスに対してプログラミングすることで、必要なことを実行できますが、実際にObjectをIRelativeToにキャストできないため、使用できます。
これは些細な例ですが、私がやろうとしていることを明確にすることを願っています。
解決
質問を理解した場合、最も一般的なアプローチは、非汎用ベースインターフェイス、つまり
を宣言することです。internal interface IRelativeTo
{
object getRelativeTo(); // or maybe something else non-generic
void setRelativeTo(object relativeTo);
}
internal interface IRelativeTo<T> : IRelativeTo
where T : IObject
{
new T getRelativeTo();
new void setRelativeTo(T relativeTo);
}
別のオプションは、主にジェネリックでコーディングすることです...つまり、次のようなメソッドがあります
void DoSomething<T>() where T : IObject
{
IRelativeTo<IObject> foo = // etc
}
IRelativeTo<T>
がDoSomething()
の引数である場合、通常ジェネリック型の引数を自分で指定する必要はありません-コンパイラが推論します-つまり、
DoSomething(foo);
ではなく
DoSomething<SomeType>(foo);
両方のアプローチには利点があります。
他のヒント
残念ながら、ジェネリックでは継承は機能しません。関数にIRelativeToが必要な場合、関数をジェネリックにすることもできます。
void MyFunction<T>(IRelativeTo<T> sth) where T : IObject
{}
正しく覚えていれば、上記の関数を使用する場合、型を指定する必要さえありません。コンパイラは、指定された引数に基づいてそれを判断する必要があります。
クラスまたはメソッド内でこれらのIRelativeToオブジェクトの1つへの参照を保持したい場合(そしてTが何であるか気にしない場合)、このクラス/メソッドを再びジェネリックにする必要があります。
同意しますが、少し苦痛です。
IRelativeToがIObjectを処理することだけが必要な場合は、ジェネリックにする必要はありません:
interface IRelativeTo
{
IObject getRelativeTo();
void setRelativeTo(IObject relativeTo)
}
実装クラスはまだ汎用的かもしれませんが:
abstract class RelativeTo<T> : IRelativeTo where T : IObject
{
public virtual T getRelativeTo() {return default(T);}
public virtual void setRelativeTo(T relativeTo) {}
IObject IRelativeTo.getRelativeTo() {return this.getRelativeTo(); }
void IRelativeTo.setRelativeTo(IObject relativeTo)
{ this.setRelativeTo((T) relativeTo);
}
}
class AdminRateShift : RelativeTo<AdminRateShift>, IObject {}
これを行うことができます:
IRelativeTo irt = new AdminRateShift();
IObject o = irt.getRelativeTo();
irt.setRelativeTo(o);