You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:52:21