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

C#如何编写可接收参数为继承指定基类实例的函数的方法?

问题原因

  • 你之前查阅的委托逆变,适用场景是:如果声明了泛型委托delegate void D<in T>(T t),那么接收父类A参数的D<A>类型委托,可以赋值给接收子类B参数的D<B>类型变量,逻辑上完全成立——所有能传入D<B>的参数都是B的实例,天然属于A类型,接收A的方法肯定能处理。
  • 而你现在的需求是反过来,要把接收子类B/C参数的方法,赋值给接收父类A参数的委托,这种操作本身类型不安全:如果后续调用委托时传入了C类型的实例,接收B参数的FunB无法处理,所以编译器直接阻止了这种转换,哪怕给委托加了逆变关键字也不支持这种反向操作。

方案1:包装lambda做显式类型转换(适合确定调用时参数类型一定匹配的场景)

直接给方法套一层lambda,把传入的A类型参数强转为对应方法需要的子类类型即可,修改后的Pain方法代码如下:

public void Pain() 
{ 
    // 套一层lambda做类型转换,匹配委托签名
    Delegate funB = (A obj) => FunB((B)obj);
    Delegate funC = (A obj) => FunC((C)obj);

    Delegate fun2 = (A obj) => { };
    fun2 += funB; 

    Method(funB);
}

这个方案优势是不需要修改原有委托和Method的定义,缺点是如果调用委托时传入了不匹配的类型,运行时会抛出类型转换异常。


方案2:改用泛型委托实现类型安全(推荐)

如果想要在编译期就规避类型错误,改成泛型方案即可:

public class Test
{
    public void FunB(B obj) { }
    public void FunC(C obj) { }

    // 声明带逆变特性的泛型委托,约束参数类型继承自A
    public delegate void Delegate<in T>(T obj) where T : A;

    // Method改为泛型方法
    public static void Method<T>(Delegate<T> fun) where T : A { }

    public void Pain() 
    { 
        // 可以直接赋值,编译器自动推断T为B/C
        Delegate<B> funB = FunB;
        Delegate<C> funC = FunC;
        
        Method(funB);
        Method(funC);
    }
}

这个方案完全类型安全,编译期就能检查类型匹配问题,不会有运行时异常。


内容的提问来源于stack exchange,提问作者xavier

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 20:24:04