Перегрузка метода не может отличаться только по типу возвращаемого значения (так же как и общее определение c, только для полноты).
С другой стороны, все вызовы метода с необязательным аргументом просто компилируются в вызов со значением по умолчанию на вызывающем сайте. Так что в вашем случае компилятор превратит это
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
.
Таким образом, перед тем, как компилятор попытается разрешить любую перегрузку, он заменит любой метод, имеющий необязательные параметры.