C#中派生类实现的泛型接口为何无法赋值给父泛型接口?
问题原因与解决方案
你遇到的问题其实是对泛型逆变(in)的方向理解反了,咱们一步步拆解:
1. 协变与逆变的核心规则
先明确C#泛型接口中in和out的作用:
- 协变(
out):适用于输出位置的泛型参数(比如方法返回值),允许你将「派生类泛型实例」赋值给「基类泛型接口」。比如IMapper<..., TypeB>可以赋值给IMapper<..., IInterfaceB>,因为TypeB是IInterfaceB的子类,返回TypeB的方法自然能满足返回IInterfaceB的要求。 - 逆变(
in):适用于输入位置的泛型参数(比如方法参数),允许你将「基类泛型实例」赋值给「派生类泛型接口」。比如如果有TypeAChild : TypeA,那么IMapper<TypeA, ...>可以赋值给IMapper<TypeAChild, ...>——因为能处理TypeA的方法,肯定能处理它的子类TypeAChild。
2. 你的代码为什么报错
你现在尝试的是:
IMapper<IInterfaceA, IInterfaceB> test = new AToBMapper();
这里的问题出在in TIn参数:
AToBMapper实现的是IMapper<TypeA, TypeB>,它的MapAToB方法只能接受TypeA类型的输入;- 而
IMapper<IInterfaceA, IInterfaceB>要求实现类能接受所有IInterfaceA类型的输入(比如如果有另一个TypeA2 : IInterfaceA,你的AToBMapper根本处理不了)。
逆变in的规则是「允许用基类代替子类作为输入参数的泛型类型」,而不是反过来——你现在是想用子类TypeA代替基类IInterfaceA,这违反了逆变的设计逻辑,因为这样会导致接口要求的能力(处理所有IInterfaceA)无法被实现类满足。
3. 正确的用法
根据你的需求,有两种可行的调整方向:
方向一:如果只需要处理TypeA并返回IInterfaceB
你可以保留AToBMapper的实现,将变量声明为协变后的类型:
// 这里TOut用协变,TypeB可以向上转为IInterfaceB IMapper<TypeA, IInterfaceB> test = new AToBMapper();
方向二:如果需要处理任意IInterfaceA并返回IInterfaceB
那你需要修改AToBMapper的实现,让它直接实现IMapper<IInterfaceA, IInterfaceB>:
class AToBMapper : IMapper<IInterfaceA, IInterfaceB> { public IInterfaceB MapAToB(IInterfaceA input) { // 这里需要判断input是否是TypeA类型,或者做通用处理 if (input is TypeA a) { // 处理TypeA的逻辑 return new TypeB(); } throw new NotSupportedException("不支持的输入类型"); } } // 此时赋值就没问题了 IMapper<IInterfaceA, IInterfaceB> test = new AToBMapper();
方向三:利用逆变的正确场景
如果有一个TypeA的子类,你可以把AToBMapper赋值给接受子类的IMapper:
class TypeAChild : TypeA { } // 逆变生效:IMapper<TypeA, ...>可以赋值给IMapper<TypeAChild, ...> IMapper<TypeAChild, IInterfaceB> test = new AToBMapper();
这样就符合逆变的规则了,因为AToBMapper能处理TypeA,自然能处理它的子类TypeAChild。
内容的提问来源于stack exchange,提问作者Kobek
相关产品推荐
相关产品推荐

