Is the in parameter modifier really optional on the call site? - c#

I'm a bit confused about the in parameter modifier:
I know if I write in before a parameter it a read only reference, which is faster then passing big stuff by value. According to the documentation https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier it says that the in parameter modifier is optional on the callsite:
Specifying in for arguments at the call site is typically optional. There is no semantic difference between passing arguments by value and passing them by reference using the in modifier. The in modifier at the call site is optional because you don't need to indicate that the argument's value might be changed. You explicitly add the in modifier at the call site to ensure the argument is passed by reference, not by value. Explicitly using in has the following two effects:
First, specifying in at the call site forces the compiler to select a method defined with a matching in parameter. Otherwise, when two methods differ only in the presence of in, the by value overload is a better match.
Second, specifying in declares your intent to pass an argument by reference
When I use it in my code:
public static kAssetKind? DetermineAssetKind(in string extension)...
And I call it here:
...{FilePath = mainFile, Kind = DetermineAssetKind(Path.GetExtension(mainFile)) ?? kAssetKind.Other};
it's okay the string is passed by reference, but if I write specifically in before:
DetermineAssetKind(in Path.GetExtension(mainFile))
then I get an error that it could be passed by reference. So there is a difference between an in on callsite and it says "Second, specifying in declares your intent to pass an argument by reference" but I thought it will pass it by reference even if I don't use in at the callsite? And does it even make sense to pass a string as in reference because classes are reference?

I think you are misunderstanding the article.
The way I understand it is that considering the following method:
void Foo(in SomeBigValueType t)
{ ... }
The following two calls are the same:
SomeBigValueType v;
Foo(v);
Foo(in v);
Your issue seems to be unrelated to the article. in needs a storage location (aka variable). In your second example you aren’t passing one so you get an error; you’d get the same error with ref or out.

Related

Var Keyword as optional parameter in c#

Can we use var keyword in methods optional parameter? Keyword var should be initialised while declared. Can't I use this as a default parameter, because default parameter is initialised while declared.
For example:
public void MyMethod(string param, var optionalParam = string.Empty)
When i try to do this then C# compiler is giving me an error, some one please explain.
Error:
The contextual keyword 'var' may only appear within a local variable declaration
Default parameter value for 'optionalParam' must be a compile-time constant
You can't use the var keyword for optional parameters, mostly because you can't use the var keyboard for any parameters, even non-optional parameters. var can only be used for local method variables, not for method parameters, fields or any other place. The compiler error here is clear and unambiguous.
That said, you have a second error there, also explained by the compiler, that you can't set an optional parameter's default value to a non-const value. string.Empty is non-const. You'll have to use null, or explicitly "" there.
First of all, String.Empty is not declared with const so it can't be used as the default value for optional parameters anyway. Use "" instead.
Though it seems perfectly okay to use var here, C# does not allow that.
According to the C# language specification section 10.6.1:
Method parameters The parameters of a method, if any, are declared by
the method’s formal-parameter-list.
formal-parameter-list:
fixed-parameters

 fixed-parameters , parameter-array
parameter-array
fixed-parameters:

 fixed-parameter

 fixed-parameters , fixed-parameter
fixed-parameter:
attributes(opt) parameter-modifier(opt) type identifier default-argument(opt)
default-argument:
= expression
parameter-modifier:

 ref
out
this
parameter-array:
attributes(opt) params array-type identifier
The formal parameter
list consists of one or more comma-separated parameters of which only
the last may be a parameter-array. A fixed-parameter consists of an
optional set of attributes (§17), an optional ref, out or this
modifier, a type, an identifier and an optional default-argument. Each
fixed-parameter declares a parameter of the given type with the given
name. The this modifier designates the method as an extension method
and is only allowed on the first parameter of a static method.
Extension methods are further described in §10.6.9.
Note how it says type under the fixed-parameter grammar? That means it needs a type there, not var.
On the other hand, here is what the specs say about local variable declarations where var can be used.
section 8.5.1 Local variable declarations
local-variable-declaration:
local-variable-type local-variable-declarators
local-variable-type:
type

var
local-variable-declarators:
local-variable-declarator
local-variable-declarators , local-variable-declarator
local-variable-declarator:
identifier
identifier = local-variable-initializer
local-variable-initializer:

 expression
array-initializer
As you can see, for local-variable-type, it is either type or var. This shows that the specs treat type and var as different things. When it says type it must be a type, not var.
As the others have mentioned you cannot use var in the parameter list.
Now not having written the spec I can't tell you why you can't. However there is a very good reason why you shouldn't.
The parameter list is used to tell whoever calls the method what to put in. As a result it should clearly state that. If you use MyFunc(var param=Myconstant) I have no idea what type param should be.
I would guess that is why var is only allowed in local variables. Since local variables are not meant to be used by any other part of the program its fine if they don't spell out explicitly what they are.

Using a derived class in c# out parameters [duplicate]

In c# I am trying to implement a method which I can use to bind data to any control I pass to it (provided of course the control is derived from a databoundcontrol object)
given the method
public void CTLBindData(ref DataBoundControl ctl){ ... }
I get an error when trying to pass derived control to the function
for example the following code
DropDownList lister = new DropDownList();
CTLBindData(ref lister);
Generates a conversion error
Ok I can accept that, but the following confuses me (probably because I am used to c++ not c#)
CTLBindData(ref (DataBoundControl)lister);
in this case I get the error
"A ref or out argument must be an assignable variable"
For clarification A Dropdownlist inherits from a list control which inherits from a DataBoundControl
This makes no sense to me I should be able to pass in any object that has been derived from a databound control. It seems that the explicit typecast is causing the problem.
Any clues as to what I am doing wrong?
DC
Do the cast prior to calling the method like this:
DataBoundControl countrol = (DataBoundControl)lister;
CTLBindData(ref control);
C# requires that any ref parameters be of the exact type (no polymorphism) and the reference of that type must be assignable. This is why you must create the reference via explicit cast in a separate step so the method has a reference of the correct type to which a value can be assigned.
For more information about this topic please see Why do ref and out parameters not allow type variation? by Eric Lippert:
If you have a method that takes an "X"
then you have to pass an expression of
type X or something convertible to X.
Say, an expression of a type derived
from X. But if you have a method that
takes a "ref X", you have to pass a
ref to a variable of type X, period.
Why is that? Why not allow the type to
vary, as we do with non-ref calls?
Use a generic function with the appropriate type parameter constraint:
public void CTLBindData<TControl>(ref TControl ctl)
where TControl : DataBoundControl
{ ... }
The type is inferred directly in the call, and the ocnstraint ensures that the control is of the appropriate type.
Andrew Hare is correct, but in this case, you may not even want to be using the ref. Objects in C# are already passed by reference*. (As opposed to value types, which are not passed by reference unless you use the ref keyword.) There are very few cases that I can think of where you'd actually need to pass a reference type in that way. Without the ref, your original code should work just fine.
**Not really, but it's easier to understand that way if you come from a non-C# background. The reference is actually passed by value. There is an excellent article on the exactly how this all works.*
Andrew Hare answered very well.
Your object must need something inside to use REF or OUT. For example: could be null.
DropDownList lister = new DropDownList();
lister = null;
CTLBindData(ref lister);

Assignment operator (=) in argument of Method Definition

See below method definition.
What is it called in C# where the equals sign is in method parameter.
Does it default method parameter initialization??
public List<Iabc> MyMethod(out List<Ixyz> faces, Type typeXYZ = null, int flag = -1)
{
//...
//...
}
NOTE: Here Iabc and Ixyz are any Interfaces.
They're called optional (or named) arguments. MSDN usually has these things explained pretty well:
Named and Optional Arguments (C# Programming Guide)
When using named arguments, be aware that changing argument names will break code. (where named parameters are used)
Also, remember that the default value is actually stored in the call site meaning that if you at some later point change the default value, code that is calling the method and was compiled before the change, will still use the old value. it might not matter in all situations but its something to be aware of.
That's an optional argument in C# 4.0

Which of these two is the correct term: Named parameters or Named arguments?

With respect to C# 4.0, which of these two is the correct term: Named parameters or Named arguments? I find many occurences of both terms hence am quite confused how to mention them (say in formal documentation)?
parameters have always been named; in the context of supplying values for a method, they are arguments - however, then name that you are specifying is the parameter name. So I can see how it would become mixed up ;p But in the context, we are supplying to name for the compiler to use to resolve the argument, so "named arguments" ftw.
More specifically:
7.5.1 Argument lists
An argument with an argument-name is referred to as a named argument, whereas an argument without an argument-name is a positional argument. It is an error for a positional argument to appear after a named argument in an argument-list.
MS itself refers to them as "named arguments". They made the language; I'd stick with what they use.
(Unless anyone finds stuff on MSDN referring to "named parameters" in the context of C#.
EDIT: Someone did. Use whatever the hell terminology you want. :)
I've seen them used interchangeably, however I like to use parameters in regards the definition, and arguments in regards the values passed. For example, the following class has a "type parameter":
class A<T> { }
But the following declaration has a "type argument":
var a = new A<string>();
Quoting from the C# 4 Specification:
Since a type parameter can be instantiated with many different actual type arguments, type parameters have slightly different operations and restrictions than other types.
Another quote:
A fixed-parameter with a default-argument is known as an optional parameter, whereas a fixed-parameter without a default-argument is a required parameter.
The only time (AFAIKnew) the C# spec refers to "named arguments" is in regards to Attributes. But when to referring to the new feature, they use "named paramters". So, I would follow that pattern.
Update
Marc has a good point that parameters have always been named, but that doesn't mean that arguments can be named now too. The name still belongs to the parameter and the argument is supplied to it. With the new "named parameters" feature, there are potentially two parts to supplying arguments: the argument itself, and the name of the parameter it is being supplied to.
// The part before the : is the named parameter,
// and the part after the : is the argument
SomeMethod(someParam: someArg);
I know this is splitting hairs, but I still think it's a valid point. As far as I'm concerned, you will be understood whether you use "named parameter" or "named argument". (Plus, section 7.5.1 is still glaring at me.)
In my personal opinion I think that 7.5.1 has it backwards, which is also confirmed by 7.5.1.1 which states:
If no unique parameter list is found, a parameter list with inaccessible names and no optional parameters is constructed, so that invocations cannot use named parameters or omit optional arguments.
In the call you name the parameter that should accept the argument you pass to it.
public static void SayHello(string name = "John Doe", int age = 30)
{
Console.WriteLine("Hello {0}, I see you're {1} years old.", name, age);
}
static void Main(string[] args)
{
SayHello(age:42);
}
Inside Main I haven't passed any argument to the "name" parameter and I don't need to since it has a default value which makes the argument optional (the parameter is not optional since it obviously exist in the SayHello function). I have however specified that the argument 42 should be passed to the "age" parameter (in other words I have named the parameter in the call). If I could name the arguments I should be able to give them arbitrary names:
SayHello(language:"vFred", version:7);
The only reason I would see for allowing "named arguments" would be if I use an API which doesn't use descriptive names for the parameters of a method. Then at least I could at the caller site name the arguments so it makes sense. But alas C# does not allow you to give your arguments any names, it does however allow you to specify the name of the parameter that should accept the argument.
This reasoning is of course only valid if you don't think that arguments and parameters are interchangeable but rather that parameters are the list on the called site while arguments are on the caller site, which is at least how C++ defines them.

OptionalAttribute parameter's default value?

MSDN's VS2010 Named and Optional Arguments (C# Programming Guide) tells us about optional parameters in C#, showing code like I'd expect:
public void ExampleMethod(int required,
string optionalstr = "default string",
int optionalint = 10)
Ok, but it also says:
You can also declare optional
parameters by using the .NET
OptionalAttribute class.
OptionalAttribute parameters do not
require a default value.
I read MSDN's OptionalAttribute page, and done searches online (which shows lots of people claiming OptionalAttribute parameters can't be consumed by C# -- I'm guessing these comments were made before C# 4?), but I can't find the answer to two questions:
If I use OptionalAttribute to define a C# parameter as optional:
what value will be used if I call that method and don't specify that parameter's value?
will that value be evaluated at compile time or runtime?
The rules are this:
For parameters of type object, Type.Missing is passed.
For other reference types, null is passed.
For value types, the default of the value type is passed.
For Nullable<T> this means that you will get a Nullable<T> instance which is equal to null (the HasValue property will return false)
Note that in the case of everything except parameters of type object, it's the equivalent of default(T).
I was a little surprised, as the C# 4.0 specification didn't indicate what the outcome would be, and I'd expect it to be there.
Also (as indicated by Scott Rippey in the comments), this is evaluated at compile-time, this is not a run-time operation, meaning that if you have calls to this method in other assemblies which are already deployed, and you change the optional value, the default passed to the method will not change unless you compile everything that makes the call against the method in the assembly.

Categories

Resources