Menol
Menol

Reputation: 1348

Why does C# allow overloads when the only difference is an optional parameter?

Why does C#/Framework allow me to use an optional parameter to create an overload that it otherwise does not allow?

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
{
}

When I try above overloads I get the following error which I agree with:

Error CS0111 Type 'DataHelpers' already defines a member called 'NullableConvert' with the same parameter types


However, if I add an optional parameter to one of the methods as shown below then I am allowed to use these overloads (please note 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
{
}

When I run following the run time resolves correct overloads without the optional parameter

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

How are the compiler/runtime able to resolve the overload without the optional parameter?

Why did I get the error at the first place if the methods could be resolved?

Upvotes: 3

Views: 241

Answers (2)

MakePeaceGreatAgain
MakePeaceGreatAgain

Reputation: 37000

A method-overload is not allowed to only differ on the return-type (as well as the generic definition, just for completeness).

On the other hand all calls to a method having an optional argument are just compiled to a call with the with default-value on the calling-site. So in your case the compiler will turn this

NullableConvert(DB.Value, Convert.ToString)

into this:

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

while changing the method

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

into this:

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

However there´s no reason to also replace the method for the struct as well, because there is no optional parameter defined for that method. So in the IL there exist the following two methods:

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
{
}

A call to NullableConvert(DB.Value, Convert.ToString) will therefor not be compiled to the forementioned overload, because there already is a perfect match for TOut: struct.

So in short before the compiler tries to resolve any overload, it replaces any method having optional parameters.

Upvotes: 5

Manfred Wippel
Manfred Wippel

Reputation: 2066

The return value is not part of the signature of a method. as already answered here

And also in the microsoft docs

Upvotes: 1

Related Questions