当唯一的区别是一个可选参数时,为什么C#允许重载



为什么C#/Framework允许我使用一个可选参数来创建一个它不允许的重载?

public static TOut? NullableConvert<TOut>(object source, Func<object, TOut> converter) where TOut : struct
{
}
public static TOut NullableConvert<TOut>(object source, Func<object, TOut> converter) where TOut : class
{
}

当我尝试以上过载时,我会得到以下错误,我同意:

错误CS0111类型"DataHelpers"已定义名为具有相同参数类型的"NullableConvert">


但是,如果我向下面所示的方法之一添加了一个可选参数,那么我就可以使用这些重载(请注意object x = null(。

public static TOut? NullableConvert<TOut>(object source, Func<object, TOut> converter) where TOut : struct
{
}
public static TOut NullableConvert<TOut>(object source, Func<object, TOut> converter, object x = null) where TOut : class
{
}

当我按照运行时运行时,解决了正确的过载,而没有可选参数

long? x = DataHelpers.NullableConvert(DBNull.Value, Convert.ToInt64);
string y = DataHelpers.NullableConvert(DBNull.Value, Convert.ToString);

编译器/运行时如何在没有可选参数的情况下解决过载?

如果这些方法可以解决,为什么我一开始就出现错误?

方法重载不允许只在返回类型上不同(以及泛型定义,只是为了完整性(。

另一方面,对具有可选参数的方法的所有调用都只编译为调用站点上具有默认值的调用。所以在你的情况下,编译器会把这个

NullableConvert(DB.Value, Convert.ToString)

进入这个:

NullableConvert(DB.Value, Convert.ToInt64, null)

同时更改方法

public static TOut NullableConvert<TOut>(object source, Func<object, TOut> converter, object x = null) where TOut : class
{
}

进入这个:

public static TOut NullableConvert<TOut>(object source, Func<object, TOut> converter, object x) where TOut : class
{
}

然而,没有理由也替换struct的方法,因为没有为该方法定义可选参数。因此,在IL中存在以下两种方法:

public static TOut NullableConvert<TOut>(object source, Func<object, TOut> converter, object x) where TOut : class
{
}
public static TOut? NullableConvert<TOut>(object source, Func<object, TOut> converter) where TOut : struct
{
}

因此,对NullableConvert(DB.Value, Convert.ToString)的调用将不会编译为前面提到的重载,因为已经存在对TOut: struct的完美匹配。

简而言之,在编译器试图解决任何重载之前,它会替换任何具有可选参数的方法。

返回值不是方法签名的一部分。正如这里已经回答的

也在微软文档中

最新更新