Changes on overloaded method behaviour between visual studio 2013 and 2015 - c#

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:
The expanded form is used if the function member was applicable only in the expanded form.
Optional parameters with no corresponding arguments are removed from the parameter list
The parameters are reordered so that they occur at the same position as the corresponding argument in the argument list.
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:
If Mp is a non-generic method and Mq is a generic method, then Mp is better than Mq.
No difference here
Otherwise, if 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.
No difference here; both are in their expanded form
Otherwise, if 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.
Not 100% on this one. Both our argument lists use 2 of the parameters from the original function definitions. I think this is solely meant to distinguish between one case where both arguments went into the same params array and one where one went into the array and one went into a normal argument.
Otherwise if all parameters of 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.
Aha! Our first argument list is missing 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.

Related

Optional parameter & params enum in method signature in C#

My current issue is that I cannot use the method I wrote in the way I expected I could.
This is my signature :
IList<FileInfo> GetFiles(string name = "*", params SignalState[] states);
If relevant, please note that SignalState is an enum.
I would expect to be able to call this method with either one argument (string OR SignalState), none, or both of them. It works if I use both arguments, if I use none of them, or if I use only the name.
Right now I would expect that only providing a SignalState would work, because the compiler would assume the first parameter is optional and my SignalState fits the second parameter of the signature.
It does not work, and the error is quite clear, its expecting a name.
So I have tried changing the signature to this :
IList<FileInfo> GetFiles([Optional] string name, params SignalState[] states);
and obviously add a bit of logic to handle my wildcard default value for the string, but I still face the exact same problem.
I have also tried switching the two paramters, params SignalState first and the string last, but the compiler specifically says params should be last and shows an error in the signature.
Could someone explain to me why it is behaving the way it is ? I would expect to be able to jump to the second param since the first one is optional.
Is my only solution to implement as many overloads as necessary to be able to call my method with only a SignalState ? Or am I missing something in how optional parameters work ?

Method overloaded with "params" keyword behavior [duplicate]

Say I have the following methods:
public static void MyCoolMethod(params object[] allObjects)
{
}
public static void MyCoolMethod(object oneAlone, params object[] restOfTheObjects)
{
}
If I do this:
MyCoolMethod("Hi", "test");
which one gets called and why?
It's easy to test - the second method gets called.
As to why - the C# language specification has some pretty detailed rules about how ambiguous function declarations get resolved. There are lots of questions on SO surrounding interfaces, inheritance and overloads with some specific examples of why different overloads get called, but to answer this specific instance:
C# Specification - Overload Resolution
7.5.3.2 Better function member
For the purposes of determining the
better function member, a
stripped-down argument list A is
constructed containing just the
argument expressions themselves in the
order they appear in the original
argument list.
Parameter lists for each of the
candidate function members are
constructed in the following way:
The expanded form is used if
the function member was applicable
only in the expanded form.
Optional parameters with no
corresponding arguments are removed
from the parameter list
The parameters are reordered
so that they occur at the same
position as the corresponding argument
in the argument list.
And further on...
In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …, QN} are equivalent > (i.e. each Pi has an identity conversion to the corresponding Qi), the following
tie-breaking rules are applied, in order, to determine the better function member.
If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.
Otherwise, if 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.
Otherwise, if 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.
The bolded tie-breaking rule seems to be what is applying in this case. The specification goes into detail about how the params arrays are treated in normal and expanded forms, but ultimately the rule of thumb is that the most specific overload will be called in terms of number and type of parameters.
The second one, the compiler will first try to resolve against explicitly declared parameters before falling back on the params collection.
This overload is tricky...
MyCoolMethod("Hi", "test") obviously calls the 2nd overload, but
MyCoolMethod("Hi"); also calls the 2nd overload. I tested this.
Maybe since both of the inputs are objects, the compiler assume anything passed in will be an array of objects and completely ignores the 1st overload.
It probably has to do with the Better function member resolution mentioned by womp
http://msdn.microsoft.com/en-us/library/aa691338(v=VS.71).aspx

How to read MSDN API correctly. (eg. IDbSetExtensions.AddOrUpdate)

For example, if you go to IDbSetExtensions.AddOrUpdate Method (IDbSet, Expression>, TEntity[]) page on MSDN -- http://msdn.microsoft.com/en-us/library/hh846514(v=vs.103).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1 --, you see that it takes three params. IDbSet, Expression and TEntity.
But what people usually write is like the below.
AddOrUpdate(item => new{item.Text}, itemArray); -- for the "seed method" within migrations.
My questions are:
How come there's only 2 params provided, not 3 and it's still ok?
What will be the difference between "AddOrUpdate(item => item.Text, itemArray)" and "AddOrUpdate(item => new{item.Text}, itemArray)" where first one there's no new operator.
When you're programming, do I need to know what every single line (within a project template) is doing?
I started project using template, so I don't have complete understanding of what it's doing but it sure takes time to dissect the whole template.
Method you're looking at is an extension method. That's why you can call it with the first parameter missing.
If you look closely, you can see that the method is static, which means it should be called using the class name, which is IDbSetExtensions.AddOrUpdate. However, because it is an extension method (this modifier in front of the first method argument makes that happen), you can call it as if it was an instance method of the type of the first method argument, in this case IDbSet<TEntity>.
Read more about extension methods on MSDN: Extension Methods (C# Programming Guide)
For AddOrUpdate(item => item.Text, itemArray) generic type TObject will get inferred to be whatever the type of item.Text is (probably a string). For AddOrUpdate(item => new{item.Text}, itemArray) is will be inferred as anonymous type, with one property.
You definitely should.
How come there's only 2 params provided, not 3 and it's still ok?
The method call AddOrUpdate(item => new{item.Text}, itemArray) only passes two parameters, which is the same number of parameters as AddOrUpdate(item => item.Text, itemArray).
What's the difference
The method call with new {item.Text} returns an anonymous type with (assuming item.Text is a string) a string property called Text that has the value of item.Text. The other method returns a string.
Do you need to know what every single line is doing?
No. Only, the compiler needs to know. But it will help you write software if you know what the code does.

Visual Studio chooses wrong constructor when a library isn't referenced?

I am using Visual Studio 2010 with two projects.
One contains a project referencing Microsoft's Exchange.WebServices dll(ver1.2) for accessing ExchangeServices. I created a class which contains some helper methods and wrappers to carry out various tasks while connected to an Exchange server(through the ExchangeService API). The ExchangeService constructor can accept an enum of ExchangeVersion, to specify the server version info. So I created two constructors within my class.
public class ExchangeConnector(string ver)
{
// Property assignments
}
public class ExchangeConnector(ExchangeVersion ver)
:this(ver.toString()) //Using(or not using) "this", doesn't seem to matter...
{ }
I created the constructor which accepts a string parameter, so that other projects don't necessarily need to add the Exchange.WebServices library.
But then I ran into an un-foreseen issue.
When I create an instance of ExchangeConnector("Exchange2007_SP1") in my second project(that does not contain a reference to the Exchange.WebServices dll), Intellisense doesn't pick the right constructor and doesn't show any pre-compile errors. When I force the build, though, I get the following error:
Error: The type 'Microsoft.Exchange.WebServices.Data.ExchangeVersion' is defined
in an assembly that is not referenced. You must add a reference to assembly
'Microsoft.Exchange.WebServices, Version=14.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35'.
I am not even using the constructor with the ExchangeVersion enum reference, but it requires me to have a reference to it?
If I comment out the constructor with the ExchangeVersion enum, everything compiles, works, no run-time errors.
OR
If I modify the overload constructor so Intellisense can't possibly confuse the two, such as:
public class ExchangeConnector(string url, ExchangeVersion ver)
{
// Property assignments
}
When I call ExchangeConnector("Exchange2007_SP1"), the code compiles and works fine. No runtime errors.
It is almost as though VS can't resolve which constructor to properly use. Now I know I can add the reference to the second project and be done with it, but I am curious as to why VS is doing this. Any ideas?
After inspiration from Scott(the other one) and the link provided by CodeCaster, I think I finally found my answer.
It as part of the C# Language Specification(Visual Studio .Net 2003 Edition).
In Section 10.10 Instance Constructors:
An instance constructor initializer of the form base(argument-listopt) causes an instance constructor from the direct base class to be invoked. That constructor is selected using argument-list and the overload resolution rules of Section 7.4.2. The set of candidate instance constructors consists of all accessible instance constructors contained in the direct base class (including any default constructor, as defined in Section 10.10.4). If this set is empty, or if a single best instance constructor cannot be identified, a compile-time error occurs.
Diving down further to the definition...
In Section 7.4.2 Overload resolution:
Once the candidate function members and the argument list have been identified, the selection of the best function member is the same in all cases:
Given the set of applicable candidate function members, the best function member in that set is located.
If the set contains only one function member, then that function member is the best function member.
Otherwise, the best function member is the one function member that is better than all other function members with respect to the given argument list, provided that each function member is compared to all other function members using the rules in Section 7.4.2.2.
If there is not exactly one function member that is better than all other function members, then the function member invocation is ambiguous and a compile-time error occurs.
And even further...
Section 7.4.2.2 Better function member[3]
[3][http://msdn.microsoft.com/en-us/library/aa691338(v=vs.71).aspx]
Given an argument list A with a set of argument types {A1, A2, ..., AN} and two applicable function members MP and MQ with parameter types {P1, P2, ..., PN} and {Q1, Q2, ..., QN}, MP is defined to be a better function member than MQ if
for each argument, the implicit conversion from AX to PX is not worse than the implicit conversion from AX to QX, and
for at least one argument, the conversion from AX to PX is better than the conversion from AX to QX.
When performing this evaluation, if MP or MQ is applicable in its expanded form, then PX or QX refers to a parameter in the expanded form of the parameter list.
So in summary:
A constructor with the same number of arguments must be evaluated through implicit conversion as to which function member(constructor) would be better.
Hence why I needed to add the reference to the second project so the compiler could determine which constructor was better.
If the constructors don't have the same number of arguments, evaluation doesn't need to occur, and the compiler doesn't need the reference to the second project.
It makes sense to me that if your project is referencing another project with an overloaded constructor where one of those constructors accepts a referenced library, that your calling project would need that reference to compile even though you aren't using that particular constructor. Wouldn't the compiler need that reference to decide which constructor to use? Maybe I'm missing something, but it seems logical to me that it's working correctly.

Mixing Out and Named Parameters in C#: Why Does Out Parameter Need to be Named As Well?

Short Version: A named argument following an out argument gives a compiler error, but I cannot find any support for this behaviour in the language specification.
Long Version:
I'm using the Enum.TryParse<TEnum> three parameter overload, but I would prefer to name the ignoreCase parameter to make my code clearer, a call like:
MyEnum res;
b = Enum.TryParse<MyEnum>(inputString, true, out res);
leaves the meaning of the boolean unclear (unless this method is known1). Hence I would like to use:
b = Enum.TryParse<MyEnum>(inputString, out res, ignoreCase: true);
However the compiler reports this as an error:
Named argument 'ignoreCase' specifies a parameter for which a positional argument has already been given
and the IDE highlights the ignoreCase parameter. VS2010 targeting .NET 4, and VS11 Beta targeting either 4 or 4.5 all give the same result. In all cases naming the out parameter removes the error.
b = Enum.TryParse<MyEnum>(inputString, result: out res, ignoreCase: true);
I've tried this across a number of different methods (including avoiding generics)2, both from the framework and in my assembly: always the same result: an out parameter followed by a named parameter gives an error.
I can see no reason for this error, and §7.5.1 Argument Lists of the C# Language Specification: Version 4.0 does not seem to provide any reason why an out followed by a named parameter should give an error. The text of the error seems to support an interpretation as a bug: there is no positional argument which could be a valid match for ignoreCase.
Is my reading of the specification wrong? Or is this a compiler bug?
C# 7.2 Update
This restriction on all named arguments have to follow positional arguments when calling was lifted with C# 7.2.
See https://learn.microsoft.com/en-gb/dotnet/csharp/whats-new/csharp-7-2#non-trailing-named-arguments.
1 Hence the advice in the Framework Design Guidelines to prefer enum parameters.
2 Eg: given:
private static void TestMethod(int one, float two, out string three) {
three = "3333";
}
this this call also gives the same error on the named parameter unless the out parameter is also named:
TestMethod(1, out aString, two: 1.0f);
Named parameters do not allow you to "skip" positional arguments.
Your code is parsed as passing the first two arguments—value and ignoreCase, then passing ignoreCase again.
It has nothing to do with the outness of the parameter.
You can fix it by passing the last parameter as named too.
Every positional argument needs to match, if you start rearranging the order by naming the arguments, you must rearrange all the arguments following the one you named.
So this line of code:
b = Enum.TryParse<MyEnum>(inputString, out res, ignoreCase: true);
Tries to match out res with ignoreCase, and then you come along naming that parameter again, which trips the compiler up. Likely there is another error just lurking behind the first one, that out res is not a match for ignoreCase.
So if you want to "skip" ignoreCase when dealing with positional arguments, you must name the out res argument as well.

Categories