代码改变世界

C#关于参数为null(空值)的方法调用,重载顺序选择彻底研究

  Ivony...  阅读(6015)  评论(6编辑  收藏  举报

其实这是一个很老的问题了,很久以前就在园子里看到有人对此迷惑,当时也没太在意,觉得哪会有人那么写代码。直到最近丁学君的这篇文章:“关于参数为可空值类型的多个重载的优先级”才让我对这个问题重新有了兴趣。并且做出了一个大胆的猜想,现在这个猜想已经被我验证了。

 

所有具备单向隐式类型转换或者存在继承关系的类型的方法重载,当使用null值调用时,将会使用隐式类型转换的方向来确定调用哪个方法。

 

简而言之,假设TypeA和TypeB之间存在一个隐式类型转换或者继承关系,方向是TypeA对象可以隐式转换为TypeB(TypeA存在一个到TypeB的隐式类型转换或者TypeA派生于TypeB)。

又有两个方法的重载如下:

public void MyMethod( TypeA obj ){ … }//重载A

public void MyMethod( TypeB obj ){ … }//重载B

 

那么MyMethod( null )一定会选择重载A。

 

但是这还没完,我仔细测定了各种情况的调用情况,并和装配脑袋一起分析整理了一下,还有如下结论:

 

1、对于Nullable<T>类型而言,T所拥有的运算符(包括隐式类型转换运算符)都会被投射到T?类型。比如说,int有一个隐式类型转换到long,那么int?也就会自动存在一个隐式类型转换到long?。同样的,TypeA?也有一个隐式类型转换到TypeB?(如果TypeA和TypeB是值类型)。这就解释了丁学文章中所说的问题。

 

2、如果两个类型之间存在双向的隐式类型转换,即TypeA可以隐式类型转换为TypeB,而TypeB也可以隐式类型转换为TypeA,这种情况下,使用null值调用会是一个编译错误。推广开来,如果多个类型之间存在一个闭环的隐式类型转换,比如说TypeA->TypeB,TypeB->TypeC,TypeC->TypeA,那么如果这三个类型的重载都存在的话,使用null值调用同样的编译错误,但是如果只有两个类型的重载存在(即方法重载的参数类型不存在闭环)那么也不会有错误。

 

3、数组的协变也会被看作是一个隐式类型转换,比如说TypeA派生于TypeB,则TypeA[]存在一个到TypeB[]的隐式转换,这个被称之为数组的协变。那么这个隐式转换也会被这个规则采信,即如果两个方法的参数是TypeA[]和TypeB[]的话,采用null值调用会选择TypeA[]的重载。

 

4、VB中也采用类似的规则,这一点有待装配脑袋的确认。

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
点击右上角即可分享
微信分享提示