您缺少的一件事是界面中的差异声明。该接口不是变体,除非您将其声明为:
public interface IInvoker<in TParameter, out TResult>
// ^^ ^^^
// Look! Here too!
{
TResult Invoke(TParameter parameter);
}
in
和关键字有助于强调差异的out
性质。类型对于参数是逆变的,对于in
参数是协变的out
。换句话说,假设通常的Animal : Mammal : Cat
示例,您可以这样做:
IInvoker<Mammal, Mammal> a = Whatever();
IInvoker<Cat, Mammal> b = a;
IInvoker<Mammal, Animal> c = a;
这本身并不是特别有用,但关键是您可以在IInvoker<Mammal, Mammal>
需要的任何地方使用 anIInvoker<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 */) };
解决该问题的一种方法是从界面中删除参数。使其成为调用者的私有字段,或者创建一个将调用者与其参数配对的类,如下所示:
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() };