Have have big problem with Visual Studio 2013 and 2015. In one class, i have defined this two methods:
public List<T> LoadData<T>(string connectionStringName = "", string optWherePart = "", params object[] parameter)
public List<T> LoadData<T>(string optWherePart, params object[] parameter)
I only want to call the second method like this:
....LoadData<Config_Info>("ConfigName LIKE 'Version' AND UserName LIKE '' AND PlugInName Like ?", parameter: ProductName);
If i go to definition in Visual Studio 2013, i come to the second method declaration, but in Visual Studio 2015, i come to the first. Both solutions are absolutly identically.
Even the compiled result is different, so if i compile the same solution with VS 2015, the program stops working.
This is a very strange behaviour.
Does any one has an idea, what the differences are?
This is based on the C# 5 specification, but since the C# 6 specification doesn't appear to have been published yet that's the best I can do. It's also an attempt to invoke Cunningham's Law.
As a preliminary, in the language of s7.5.3.1 ("Applicable Function Member") of the spec, both function members are applicable (either of them could be called if the other didn't exist) in their expanded form (the params object[]
can't be fulfilled by the string
ProductName
so is converted to an object
argument).
Thus we move on to s7.5.3.2 ("Better Function Member") in order to decide which of the two is the better function to call.
Firstly, a stripped-down argument list A is constructed containing just the argument expressions themselves in the order they appear in the original argument list:
{ string "ConfigName [...]", string ProductName }
Next, [p]arameter lists for each of the candidate function members are constructed in the following way:
This gives us the following:
{ string connectionStringName, object parameter }
(optWherePart
removed, params
expanded){ string optWherePart, object parameter }
(params
expanded)We then have a sequence of comparisons to make to decide which of these is the better function member. Calling one Mp
and one Mq
, these go as follows:
Mp
is a non-generic method and Mq
is a generic method, then Mp
is better than Mq
.
Mp
is applicable in its normal form and Mq
has a params array and is applicable only in its expanded form, then Mp
is better than Mq
.
Mp
has more declared parameters than Mq
, then Mp
is better than Mq
. This can occur if both methods have params
arrays and are applicable only in their expanded forms.
params
array and one where one went into the array and one went into a normal argument.Mp
have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in Mq
then Mp
is better than Mq
.
optWherePart
, which needed a default argument, so the second argument list is better! So VS2015 is wrong!... but wait. What does this last bullet even mean? Mp
and Mq
are specifically parameter lists where [o]ptional parameters with no corresponding arguments are removed. There is no way either of them could not have a corresponding argument because if they didn't, they'd have been removed.
In conclusion, I can't tell whether this is a bug in the old compiler, the new compiler... or the C# specification.
I've found a blog post by SLaks that also seems to think the old behaviour was a bug. The blog states that Roslyn had fixed this by making the compiler fail, and that's not what I see any more. Maybe they changed their minds?
Edit: Update! My Roslyn bug report resulted in a change to the compiler to ensure that, in this case, the second overload is picked. This appears to be because of the default arguments need to be substituted wording above. I still think the spec is ambiguous, so I'm disappointed that only a code change was made (and not a spec change, or even a discussion about why the second overload is the better one), but at least the VS2015 runtime beaviour is now the same as it was in VS2013.