This isn't a question on proper coding practice, I'm just working through the semantics.
lets say I have the following constructors...
public FooClass(string name = "theFoo")
{ fooName = name; }
public FooClass(string name, int num = 7, bool boo = true) : this(name)
{ fooNum = num; fooBool = boo; }
is it possible to use named arguments thusly...?
FooClass foo1 = new FooClass(num:1);
// where I'm only passing one named argument, relying on the optionals to take care of the rest
or call the constructor FooClass(string, int, bool) with no arguments? as in...
FooClass foo2 = new FooClass();
Use of named and optional arguments affects overload resolution in the following ways:
A method, indexer, or constructor is a candidate for execution if each of its parameters either is optional or corresponds, by name or by position, to a single argument in the calling statement, and that argument can be converted to the type of the parameter.
If more than one candidate is found, overload resolution rules for preferred conversions are applied to the arguments that are explicitly specified. Omitted arguments for optional parameters are ignored.
If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.
http://msdn.microsoft.com/en-us/library/dd264739.aspx
Optional parameters are defined at the end of the parameter list, after any required parameters. If the caller provides an argument for any one of a succession of optional parameters, it must provide arguments for all preceding optional parameters. Comma-separated gaps in the argument list are not supported.
Also,
A named argument can follow positional arguments, as shown here.
CalculateBMI(123, height: 64);
However, a positional argument cannot follow a named argument. The following statement causes a compiler error.
//CalculateBMI(weight: 123, 64);
Related
I'm curious why neither of the following DoInvoke methods can be called with only one params:
public class foo {
private void bar(params object[] args) {
DoInvoke(args);
}
//Error: There is no argument given that corresponds to the required formal parameter 'args' of 'foo.DoInvoke(Delegate, object[])'
private void DoInvoke(Delegate d, object[] args) {
d.DynamicInvoke(args);
}
//Error: Argument 1: cannot convert from 'object[]' to 'System.Delegate'
private void DoInvoke(Delegate d, params object[] args) {
d.DynamicInvoke(args);
}
}
I already found a way that doesn't abuse params. I'm curious why params are not expanded here.
I was able to do something similar in Lua, hence my attempt. I know Lua is far less strict, but I'm not sure which C# rule I'm breaking by doing this.
I'm curious why neither of the following DoInvoke methods can be called with only one params:
Short version: the first can't, because it has two non-optional parameters and because you're passing a value of the wrong type for the first non-optional parameter. The second can't, but only because the value you are trying to pass for the single non-optional parameter is of the wrong type; the second parameter is optional and so may be omitted as you've done.
You seem to be under the impression that in your method declaration private void bar(params object[] args), the presence of the params keyword makes the args variable somehow different from any other variable. It's not. The params keyword affects only the call site, allowing (but not requiring) the caller to specify the array elements of the args variable to be specified as if they were individual parameters, rather than creating the array explicitly.
But even when you call bar() that way, what happens is that an array object is created and passed to bar() as any other array would be passed. The variable args inside the bar() method is just an array. It doesn't get any special handling, and the compiler won't (for example) implicitly expand it to a parameter list for use in passing to some other method.
I'm not familiar with Lua, but this is somewhat in contrast to variadic functions in C/C++ where the language provides a way to propagate the variable parameter list to callees further down. In C#, the only way you can directly propagate a params parameter list is if the callee can accept the exact type of array as declared in the caller (which, due to array type variance in C#, does not always have to be the exact same type, but is still limited).
If you're curious, the relevant C# language specification addresses this in a variety of places, but primarily in "7.5.1.1 Corresponding parameters". This reads (from the C# 5 specification…there is a draft C# 6 specification, but the C# 5 is basically the same and it's what I have a copy of):
For each argument in an argument list there has to be a corresponding parameter in the function member or delegate being invoked.
It goes on to describe what "parameter list" is used to validate the argument list, but in your simple example, overload resolution has already occurred at the point this rule is being applied, and so there's only one parameter list to worry about:
• For all other function members and delegates there is only a single parameter list, which is the one used.
It goes on to say:
The corresponding parameters for function member arguments are established as follows:
• Arguments in the argument-list of instance constructors, methods, indexers and delegates:
o A positional argument where a fixed parameter occurs at the same position in the parameter list corresponds to that parameter. [emphasis mine]
o A positional argument of a function member with a parameter array invoked in its normal form corresponds to the parameter array, which must occur at the same position in the parameter list.
o A positional argument of a function member with a parameter array invoked in its expanded form, where no fixed parameter occurs at the same position in the parameter list, corresponds to an element in the parameter array.
o A named argument corresponds to the parameter of the same name in the parameter list.
o For indexers, when invoking the set accessor, the expression specified as the right operand of the assignment operator corresponds to the implicit value parameter of the set accessor declaration.
In other words, if you don't provide a parameter name in your argument list, arguments correspond to method parameters by position. And the parameter in the first position of both your called methods has the type Delegate.
When you try to call the first method, that method has zero optional parameters, but you haven't provided a second parameter. So you get an error telling you that your argument list, consisting of just a single argument (which by the above corresponds to the Delegate d parameter), does not include a second argument that would correspond to the object[] args parameter in the called method.
Even if you had provided a second argument, you would have run into the same error you get trying to call your second method example. I.e. while the params object[] args parameter is optional (the compiler will provide an empty array for the call), and so you can get away with providing just one argument in your call to the method, that one argument has the wrong type. Its positional correspondence is to the Delegate d parameter, but you are trying to pass a value of type object[]. There's no conversion from object[] to Delegate, so the call fails.
So, what's that all mean for real code? Well, that depends on what you are trying to do. What did you expect to happen when you tried to pass your args variable to a void DoInvoke(Delegate d, params object[] args) method?
One obvious possibility is that the args array contains as its first element a Delegate object, and the remainder of the array are the arguments to pass. In that case, you could do something like this:
private void bar(params object[] args) {
DoInvoke((Delegate)args[0], args.Skip(1).ToArray());
}
That should be syntactically valid with either of the DoInvoke() methods you've shown. Of course, whether that's really what you want is unclear, since I don't know what the call was expected to do.
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
What is the difference between these two fractions in C# 5.0 (both to the programmer and to the compiler and CLR):
public MyClass()
{
; // empty
}
public MyClass(int number = 1, string text = "hello")
{
; // empty
}
If you call the second ctor, then the generated MSIL contains the default parameters, like you had directly called the ctor with two parameters.
Default parameter values are only syntactical sugar of C#... and should not be used. Use overloaded methods/ctors instead.
Have a look at http://lostechies.com/jimmybogard/2010/05/18/caveats-of-c-4-0-optional-parameters/
It is just like any function, the constructor with parameters will need them. The compiler will automatically add a default constructor if none is provided, but only if no other constructor definition is supplied. If you include a constructor with parameters, you can no longer use the default constructor and must explicitly define it.
Can I have two same function name with same parameters but different meaning.
For example:
public void test(string name)
public void test(string age)
Thank you.
No, you can't. The signature is not different - it doesn't matter what the parameter names are.
Methods are declared in a class or struct by specifying the access level such as public or private, optional modifiers such as abstract or sealed, the return value, the name of the method, and any method parameters. These parts together are the signature of the method.
http://msdn.microsoft.com/en-us/library/ms173114.aspx
Like a few other answers have stated, consider the type of data you're taking in. Name is indeed a typical string, but does age have to be? If you allow it to be a - for example - int then you can overload your method as you wish.
No, you cannot overload on a return type or a parameter name. Unlike some other languages (most notably, Objective C1) parameter name is not part of the signature of your function.
The signature of a method consists of the name of the method and the type and kind (value, reference, or output) of each of its formal parameters, considered in the order left to right. The signature of a method specifically does not include the return type, nor does it include the params modifier that may be specified for the right-most parameter.
1 even there it's not exactly the parameter name that becomes part of the selector.
You can have static and non-static methods with the same name, but different parameters following the same rules as method overloading, they just can't have exactly the same signature.
No.
Signatures and Overloading
If you need a method with different meaning why won't you create a method with a different name? It would be confusing to use the same method name for different things on the same object.
You could mix together these methods using optional parameters and default values:
public void test(string name = null, string age = null)
{
if (name != null)
{
// Do something
}
else if (age != null)
{
// Do something else
}
}
And you could call this method like that:
test(name: "John");
test(age: "30");
Not very clean, but still useable.
No - the compiler throws an error because compiler use parameters to detemine which method to call, not the return type.
NO.
An OVERLOADED FUNCTION must have different SIGNATURE.
i.e.- arguments should be different, either in terms of number of arguments or order of different datatypes arguments.
I've begun to notice at times when I'm making method calls in C# that the names of the parameters for the method I'm calling will show up in the intellisense list appended with a colon, and that I can then format the method call thusly:
MethodCall(parameter1:value1, parameter2:value2);
Is this a new language feature? It reminds me of the way you can call stored procedures in SQL and specify parameter names like so:
spDoSomeStuff #param1 = 1, #param2 = 'other param'
Is this a similar feature? If so, to what end? If not, what is it and what is it to be used for.
It's a new feature. See here: http://msdn.microsoft.com/en-us/library/dd264739.aspx
Named parameters are standard in ObjectiveC for instance. It takes some time to get used to them but they are a good thing. Only from looking you can tell what a parameter is meant for.
It is worth mentioning, unlike optional parameters, you can skip certain arguments and pass only the parameters you are interested in.
public void Example(int required, string StrVal = "default", int IntVal = 0)
{
// ...
}
public void Test()
{
// This gives compiler error
// Example(1, 10);
// This works
Example(1, IntVal:10);
}
Named parameters allow you explicitly set the value of arguments in a custom order independent of the signature. Method signatures are defined by the argument types, ie, Foo( int i, bool b ), which will only accept arguments of type int and bool in that order. Named arguments allow you to pass b first and i second.
Scott Gu has introduced this new feature in his blog:
Optional Parameters and Named Arguments in C# 4
It's the Named and Optional Parameters that came in with C# 4.