C#中重载方法的一些总结
新建一个.NET Core控制台项目,我们来看看C#中重载方法的一些注意事项。
C#中多个重载方法之间的参数如果有继承关系,那么调用方法时,会调用与传入参数类型最接近的重载方法
我们来举个例子,下面我们定义了两个重载方法Do,它们的参数类型A和B是继承关系,类B继承类A,那么我们在调用Do方法时,到底调用的是哪一个重载呢?
代码如下:
using System; namespace NetCoreOverloadParameters { /// <summary> /// 类A /// </summary> class A { } /// <summary> /// 类B继承类A /// </summary> class B : A { } class Program { /// <summary> /// 方法Do /// </summary> /// <param name="a">参数类型为A</param> static void Do(A a) { Console.WriteLine("Do A"); } /// <summary> /// 方法Do /// </summary> /// <param name="a">参数类型为B</param> static void Do(B a) { Console.WriteLine("Do B"); } static void Main(string[] args) { A a = new B(); B b = new B(); Do(a);//因为传入Do方法的类型是A,所以这里调用Do(A a) Do(b);//因为传入Do方法的类型是B,所以这里调用Do(B a) Do(new A());//因为传入Do方法的类型是A,所以这里调用Do(A a) Do(new B());//因为传入Do方法的类型是B,所以这里调用Do(B a) Do(null);//当传入null给Do方法时,这里调用的是Do(B a),说明优先调用的是继承链中参数为子类B的重载方法 Do((A)null);//因为传入Do方法的类型是A,所以这里调用Do(A a) Console.WriteLine("Press any key to end..."); Console.ReadKey(); } } }
执行结果如下:
所以我们可以看到,实际上在每次调用Do方法时,C#会选择调用和传入参数类型最接近的重载方法。
如果我们现在注释掉代码中的重载方法Do(B a),由于现在代码中只有一个Do方法了,所以所有的调用都会调用Do(A a):
using System; namespace NetCoreOverloadParameters { /// <summary> /// 类A /// </summary> class A { } /// <summary> /// 类B继承类A /// </summary> class B : A { } class Program { /// <summary> /// 方法Do /// </summary> /// <param name="a">参数类型为A</param> static void Do(A a) { Console.WriteLine("Do A"); } /// <summary> /// 方法Do /// </summary> /// <param name="a">参数类型为B</param> //static void Do(B a) //{ // Console.WriteLine("Do B"); //} static void Main(string[] args) { A a = new B(); B b = new B(); Do(a); Do(b); Do(new A()); Do(new B()); Do(null); Do((A)null); Console.WriteLine("Press any key to end..."); Console.ReadKey(); } } }
执行结果如下:
C#中如果有签名相同的泛型方法和非泛型方法,那么C#会优先考虑调用非泛型方法
我们来看看下面这个例子,我们在代码中,定义了三个Do方法,其中一个非泛型方法和两个泛型方法,那么我们在调用Do方法时,C#会优先考虑调用非泛型方法:
using System; namespace NetCoreOverloadParameters { /// <summary> /// 类A /// </summary> class A { } /// <summary> /// 泛型静态类Container<T1> /// </summary> static class Container<T1> { /// <summary> /// 方法Do /// </summary> /// <param name="a">参数类型为A</param> public static void Do(A a) { Console.WriteLine("Do A"); } /// <summary> /// 方法Do /// </summary> /// <param name="t1">参数类型为T1</param> public static void Do(T1 t1) { Console.WriteLine("Do T1"); } /// <summary> /// 方法Do /// </summary> /// <typeparam name="T2">类型参数T2</typeparam> /// <param name="t2">参数类型为T2</param> public static void Do<T2>(T2 t2) { Console.WriteLine("Do T2"); } } class Program { static void Main(string[] args) { A a = new A(); Container<A>.Do(a);//C#会优先考虑非泛型的方法,来匹配传入Do方法的类型,所以这里会调用重载方法Do(A a),这会导致泛型重载方法Do(T1 t1),无法被调用到 Container<object>.Do((object)a);//将静态类Container<T1>的类型参数<T1>定义为object后,再给Do方法传入object类型的参数,这样C#就会优先调用泛型重载方法Do(T1 t1)了 Container<A>.Do<A>(a);//由于这里我们显式声明了类型参数<T2>,所以C#知道我们在这里要调用的是重载方法Do<T2>(T2 t2) Console.WriteLine("Press any key to end..."); Console.ReadKey(); } } }
执行结果如下:
在这个例子中,我们可以看到,由于我们在Main方法中调用Container<A>.Do(a)时,其可以匹配两个签名相同的重载方法,一个是非泛型方法Do(A a),另一个是泛型方法Do(T1 t1),但是C#优先选择的是非泛型方法Do(A a),这导致了当传入Do方法的参数类型是A时,泛型方法Do(T1 t1)无法被调用到。
关于泛型方法的重载问题,可以参考:Generic methods and method overloading
C#中扩展方法和非扩展方法的重载
关于这个讨论,可以参考:C#中如果类的扩展方法和类本身的方法签名相同,那么会优先调用类本身的方法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2019-03-13 SQL Server 索引中include的魅力(具有包含性列的索引)(转载)
2017-03-13 维度属性的KeyColumns如果是Integer类型,那么维度表中该列的值不能有为null的