欠落していることの1つは、インターフェースの差異宣言です。次のように宣言しない限り、インターフェースはバリアントではありません。
public interface IInvoker<in TParameter, out TResult>
// ^^ ^^^
// Look! Here too!
{
TResult Invoke(TParameter parameter);
}
in
andout
キーワードは、差異の性質を強調するのに役立ちます。タイプは、パラメーターに関しては反変であり、in
パラメーターに関しては共変out
です。つまり、通常のAnimal : Mammal : Cat
例を想定して、これを行うことができます。
IInvoker<Mammal, Mammal> a = Whatever();
IInvoker<Cat, Mammal> b = a;
IInvoker<Mammal, Animal> c = a;
それ自体は特に便利ではありませんが、要点は、またはIInvoker<Mammal, Mammal>
が必要な場所ならどこでも使用できるということです。IInvoker<Cat, Mammal>
IInvoker<Mammal, Animal>
IInvoker<,>
また、あなたの質問には重要な欠落があります。実装のセットで正確に何をしたいですか?(「...のさまざまな実装のセットを処理したいIInvoker<,>
。」)この質問への回答は、あなたの解決策につながります。AbstractParameterから継承するいくつかのオブジェクトを使用して、それらすべてを呼び出しますか?もしそうなら、リーが説明するように、あなたが望むことをすることができれば、これを妨げるものは何もないので、あなたはいくつかの問題を抱えているでしょう:
IInvoker<AbstractParameter, AbstractResult>[] invokers = { new InvokerOne(), new InvokerTwo() };
AbstractParameter[] parameters = { new ParameterOne(), new ParameterTwo() };
AbstractResult[] results = { invokers[0].Invoke(parameters[1] /* oops */), invokers[1].Invoke(parameters[0] /* oops */) };
この問題を解決する1つの方法は、インターフェイスからパラメータを削除することです。これを呼び出し元のプライベートフィールドにするか、呼び出し元とパラメーターをペアにするクラスを作成します。たとえば、次のようになります。
interface IInvokerParameterPair<out TResult>()
where TResult : AbstractResult
{
TResult InvokeTheInvoker();
}
class InvokerParameterPair<TParameter, TResult> : IInvokerParameterPair<TResult>
where TParameter : AbstractParameter
where TResult : AbstractResult
{
private IInvoker<TParameter, TResult> _invoker;
private TParameter _parameter;
public InvokerParameterPair(IInvoker<TParameter, TResult> invoker, TParameter parameter)
{
_invoker = invoker;
_parameter = parameter;
}
public TResult InvokeTheInvoker()
{
return _invoker.Invoke(_parameter);
}
}
一方、Invokeメソッドとは関係のない処理を実行する場合、呼び出し元は他の共通インターフェースを実装するか、次のような他の共通基本クラスから継承する必要があります。
public interface IProcessable { }
public interface IInvoker<in TParameter, out TResult> : IProcessable
{
TResult Invoke(TParameter parameter);
}
public class InvokerOne : IInvoker<Parameter1, Result1> { /* ... */ }
public class InvokerTwo : IInvoker<Parameter2, Result2> { /* ... */ }
IProcessable[] invokers = { new InvokerOne(), new InvokerTwo() };
またはこれ:
public interface IInvoker<in TParameter, out TResult> : IProcessable
{
TResult Invoke(TParameter parameter);
}
public abstract class Processable { }
public class InvokerOne : Processable, IInvoker<Parameter1, Result1> { /* ... */ }
public class InvokerTwo : Processable, IInvoker<Parameter2, Result2> { /* ... */ }
Processable[] invokers = { new InvokerOne(), new InvokerTwo() };