C#实现接口方法时为何触发无限递归无法返回类实例
问题描述
在.NET 6.0环境下运行以下代码时会触发无限递归,程序永远不会执行到IInterface中的DoSomething()方法,无法从接口返回Class实例。
该现象触发场景为:类中方法的返回类型与接口对应方法的返回类型一致时,编译器判定类中重新实现了接口方法,导致方法调用自身触发递归。若将方法的返回类型修改为具体类Class,代码即可正常运行,需要解释该现象的产生原因。
测试代码如下:
using System; public class Program { public static void Main() { var obj = new Class(); var ret = obj.DoSomething(); Console.WriteLine("Finished"); } } interface IInterface { IInterface DoSomething() { return new Class(); } } class Class : IInterface { // 触发无限递归 public IInterface DoSomething() => ((IInterface)this).DoSomething(); // 可正常运行 //public Class DoSomething() => (Class)((IInterface)this).DoSomething(); }
原因解析
- C# 8.0开始支持默认接口方法,接口中定义的带方法体的
DoSomething()属于默认实现,仅当实现类为该接口方法提供了有效自定义实现时,默认实现才会被覆盖,方法调用会优先走类的自定义逻辑。 - 第一种返回
IInterface的写法会触发递归,核心原因是:public IInterface DoSomething()的方法名、参数列表、返回类型和接口声明的方法完全匹配,编译器会自动将其识别为IInterface.DoSomething()的隐式实现,优先级高于接口默认实现。此时即使在方法内部将this强转为IInterface类型再调用DoSomething(),接口方法的调用是动态分派的,最终仍会绑定到类自身实现的DoSomething(),形成方法自调用,触发无限递归。 - 第二种返回
Class的写法可正常运行,核心原因是:C#的隐式接口实现要求方法返回类型必须和接口声明的返回类型完全精确匹配,协变返回特性仅支持重写基类虚方法场景,不适用隐式接口实现。因此编译器不会将返回Class的DoSomething()识别为IInterface.DoSomething()的实现,此时Class相当于没有为该接口方法提供自定义实现,强转this为IInterface后调用DoSomething()会直接执行接口定义的默认方法,返回Class实例,不存在自调用递归问题。
补充说明:如果需要在类实现接口方法(返回类型匹配接口定义)的前提下调用接口默认方法,无法通过强转当前实例为接口类型实现,需要通过其他间接方式调用,否则必然触发递归。
内容的提问来源于stack exchange,提问作者Pedro O S
相关产品推荐
相关产品推荐

