C# Co/逆变接口和可分配性

C# Co/逆变接口和可分配性,c#,covariance,contravariance,C#,Covariance,Contravariance,我认为,我对差异有一些问题,我不完全理解。我有一个带有两个类型参数的通用接口,如下所示: public interface IInvoker<TParameter, TResult> { TResult Invoke(TParameter parameter); } public abstract class AbstractParameter { public int A { get; set; } } public abstract class Abstract

我认为,我对差异有一些问题,我不完全理解。我有一个带有两个类型参数的通用接口,如下所示:

public interface IInvoker<TParameter, TResult> {
    TResult Invoke(TParameter parameter);
}
public abstract class AbstractParameter {
    public int A { get; set; }
}
public abstract class AbstractResult {
    public string X { get; set; }
}

public class Parameter1 : AbstractParameter {
    public int B { get; set; }
}
public class Result1 : AbstractResult {
    public string Y { get; set; }
}
// ... Many more types
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);
    }
}
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() };
然后我想处理一组不同的
IInvoker
实现,所以我想我可以这样做

public class InvokerOne : IInvoker<Parameter1, Result1> { /* ... */ }
public class InvokerTwo : IInvoker<Parameter2, Result2> { /* ... */ }

// ..
IInvoker<AbstractParameter, AbstractResult>[] invokers = { new InvokerOne(), new InvokerTwo() };
公共类调用器:IInvoker{/*…*/}
公共类调用器两个:IInvoker{/*…*/}
// ..
IInvoker[]调用程序={new InvokerOne(),new InvokerTwo()};
这不起作用,因为据我所知,
IInvoker
无法从
IInvoker
(和朋友)分配。首先,我认为这是在我的界面(
interface IInvoker
)上插入一些
,然后取出一些
,但这没有帮助


但我不明白为什么?据我所知,任何使用
IInvoker
的人都应该能够调用
Invoke
,对吗?我遗漏了什么?

问题是
TResult
类型参数是反变的,但您试图在作业中同时使用它们,例如

IInvoker<AbstractParameter, AbstractResult> i1 = new InvokerOne();
这是不安全的

但是,您可以拥有以下内容:

public class OtherParameter1 : Parameter1 { }
IInvoker<OtherParameter1, AbstractResult> i1 = new InvokerOne();
public类OtherParameter1:Parameter1{}
IInvoker i1=新的调用器();

在这里,
OtherParameter1
可以作为参数传递给
Invoke
,因为它始终是
Parameter1

的有效参数,您缺少的一点是界面中的差异声明。除非您声明该接口为:

public interface IInvoker<in TParameter, out TResult>
//                        ^^             ^^^
//                        Look!          Here too!
{
    TResult Invoke(TParameter parameter);
}
这本身并不特别有用,但关键是您可以在需要
IInvoker
IInvoker
的任何地方使用
IInvoker

您的问题中还遗漏了一些重要的内容:您希望如何处理您的
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 */) };
IInvoker[]invokers={newinvokerone(),newinvokertwo()};
AbstractParameter[]parameters={new ParameterOne(),new ParameterTwo()};
AbstractResult[]results={调用程序[0]。调用程序(参数[1]/*oops*/),调用程序[1]。调用程序(参数[0]/*oops*/)};
解决该问题的一种方法是从接口中删除该参数。将其设置为调用程序的私有字段,或者创建一个将调用程序与其参数配对的类,如下所示:

public interface IInvoker<TParameter, TResult> {
    TResult Invoke(TParameter parameter);
}
public abstract class AbstractParameter {
    public int A { get; set; }
}
public abstract class AbstractResult {
    public string X { get; set; }
}

public class Parameter1 : AbstractParameter {
    public int B { get; set; }
}
public class Result1 : AbstractResult {
    public string Y { get; set; }
}
// ... Many more types
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);
    }
}
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() };
接口IInvokerParameterPair()
其中TResult:AbstractResult
{
TResult InvokeTheInvoker();
}
类InvokerParameterPair:IInvokerParameterPair
其中TParameter:AbstractParameter
其中TResult:AbstractResult
{
私人IInvoker_调用程序;
私有t参数_参数;
公共InvokerParameterPair(IInvoker调用程序,TParameter参数)
{
_调用方=调用方;
_参数=参数;
}
公共TResult InvokeTheInvoker()
{
返回_invoker.Invoke(_参数);
}
}
另一方面,如果您希望执行一些与Invoke方法无关的处理,那么您的调用程序应该实现一些其他公共接口或从一些其他公共基类继承,如下所示:

public interface IInvoker<TParameter, TResult> {
    TResult Invoke(TParameter parameter);
}
public abstract class AbstractParameter {
    public int A { get; set; }
}
public abstract class AbstractResult {
    public string X { get; set; }
}

public class Parameter1 : AbstractParameter {
    public int B { get; set; }
}
public class Result1 : AbstractResult {
    public string Y { get; set; }
}
// ... Many more types
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);
    }
}
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() };
公共接口可处理{}
公共接口IInvoker:可处理
{
TResult Invoke(TParameter参数);
}
公共类调用器:IInvoker{/*…*/}
公共类调用器两个:IInvoker{/*…*/}
IProcessable[]调用程序={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() };
公共接口IInvoker:i可处理
{
TResult Invoke(TParameter参数);
}
公共抽象类可处理{}
公共类调用器:可处理的,IInvoker{/*…*/}
公共类InvokerTwo:可处理的,IInvoker{/*…*/}
可处理的[]调用程序={new InvokerOne(),new InvokerTwo()};

啊,是的,我没有想到的是
OtherParameter
调用。当然,我只会使用“正确”的实现进行调用,所以我不会对可能出现的错误进行解释:)谢谢!