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:
attributesopt parameter-modifieropt type identifier
parameter-modifier:
ref
out
parameter-array:
attributesopt 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 (§24), an
optional ref or out modifier, a type, and an
identifier. Each fixed-parameter declares a parameter of the given type
with the given name.
A parameter-array consists of an optional set of attributes (§24), a
params modifier, an array-type, and an
identifier. A parameter array declares a single parameter of the given
array type with the given name. The arraytype
of a parameter array must be a single-dimensional array type (§19.1). In a
method invocation, a parameter
array permits either a single argument of the given array type to be
specified, or it permits zero or more
arguments of the array element type to be specified. Parameter arrays are
described further in §17.5.1.4.
A method declaration creates a separate declaration space for parameters
and local variables. Names are
introduced into this declaration space by the formal parameter list of the
method and by local variable
declarations in the block of the method. All names in the declaration space
of a method must be unique;
otherwise, a compile-time error results.
Chapter 17 Classes
229
A method invocation (§14.5.5.1) creates a copy, specific to that
invocation, of the formal parameters and local
variables of the method, and the argument list of the invocation assigns
values or variable references to the newly
created formal parameters. Within the block of a method, formal parameters
can be referenced by their identifiers
in simple-name expressions (§14.5.2).
There are four kinds of formal parameters:
? Value parameters, which are declared without any modifiers.
? Reference parameters, which are declared with the ref modifier.
? Output parameters, which are declared with the out modifier.
? Parameter arrays, which are declared with the params modifier.
[Note: As described in §10.6, the ref and out modifiers are part of a
method?s signature, but the params
modifier is not. end note]
17.5.1.1 Value parameters
A parameter declared with no modifiers is a value parameter. A value
parameter corresponds to a local variable
that gets its initial value from the corresponding argument supplied in the
method invocation.
When a formal parameter is a value parameter, the corresponding argument in
a method invocation must be an
expression of a type that is implicitly convertible (§13.1) to the formal
parameter type.
A method is permitted to assign new values to a value parameter. Such
assignments only affect the local storage
location represented by the value parameter?they have no effect on the
actual argument given in the method
invocation.
17.5.1.2 Reference parameters
A parameter declared with a ref modifier is a reference parameter. Unlike a
value parameter, a reference
parameter does not create a new storage location. Instead, a reference
parameter represents the same storage
location as the variable given as the argument in the method invocation.
When a formal parameter is a reference parameter, the corresponding
argument in a method invocation must
consist of the keyword ref followed by a variable-reference (§12.3.3) of
the same type as the formal parameter.
A variable must be definitely assigned before it can be passed as a
reference parameter.
Within a method, a reference parameter is always considered definitely
assigned.
[Example: The example
using System;
class Test
{
static void Swap(ref int x, ref int y) {
int temp = x;
x = y;
y = temp;
}
static void Main() {
int i = 1, j = 2;
Swap(ref i, ref j);
Console.WriteLine("i = {0}, j = {1}", i, j);
}
}
produces the output
i = 2, j = 1
For the invocation of Swap in Main, x represents i and y represents j.
Thus, the invocation has the effect of
swapping the values of i and j. end example]
C# LANGUAGE SPECIFICATION
230
In a method that takes reference parameters, it is possible for multiple
names to represent the same storage
location. [Example: In the example
class A
{
string s;
void F(ref string a, ref string b) {
s = "One";
a = "Two";
b = "Three";
}
void G() {
F(ref s, ref s);
}
}
the invocation of F in G passes a reference to s for both a and b. Thus,
for that invocation, the names s, a, and b
all refer to the same storage location, and the three assignments all
modify the instance field s. end example]
17.5.1.3 Output parameters
A parameter declared with an out modifier is an output parameter. Similar
to a reference parameter, an output
parameter does not create a new storage location. Instead, an output
parameter represents the same storage
location as the variable given as the argument in the method invocation.
When a formal parameter is an output parameter, the corresponding argument
in a method invocation must
consist of the keyword out followed by a variable-reference (§12.3.3) of
the same type as the formal parameter.
A variable need not be definitely assigned before it can be passed as an
output parameter, but following an
invocation where a variable was passed as an output parameter, the variable
is considered definitely assigned.
Within a method, just like a local variable, an output parameter is
initially considered unassigned and must be
definitely assigned before its value is used.
Every output parameter of a method must be definitely assigned before the
method returns.
Output parameters are typically used in methods that produce multiple
return values. [Example: For example:
using System;
class Test
{
static void SplitPath(string path, out string dir, out string name) {
int i = path.Length;
while (i > 0) {
char ch = path[i ? 1];
if (ch == ’\\’ || ch == ’/’ || ch == ’:’) break;
i--;
}
dir = path.Substring(0, i);
name = path.Substring(i);
}
static void Main() {
string dir, name;
SplitPath("c:\\Windows\\System\\hello.txt", out dir, out name);
Console.WriteLine(dir);
Console.WriteLine(name);
}
}
The example produces the output:
c:\Windows\Systemhello.txt
Note that the dir and name variables can be unassigned before they are
passed to SplitPath, and that they are
considered definitely assigned following the call. end example]
Chapter 17 Classes
231
17.5.1.4 Parameter arrays
A parameter declared with a params modifier is a parameter array. If a
formal parameter list includes a
parameter array, it must be the last parameter in the list and it must be
of a single-dimensional array type.
[Example: For example, the types string[] and string[][] can be used as the
type of a parameter array, but
the type string[,] can not. end example] It is not possible to combine the
params modifier with the modifiers
ref and out.
A parameter array permits arguments to be specified in one of two ways in a
method invocation:
? The argument given for a parameter array can be a single expression of a
type that is implicitly convertible
(§13.1) to the parameter array type. In this case, the parameter array
acts precisely like a value parameter.
? Alternatively, the invocation can specify zero or more arguments for the
parameter array, where each
argument is an expression of a type that is implicitly convertible (§13.1)
to the element type of the parameter
array. In this case, the invocation creates an instance of the parameter
array type with a length corresponding
to the number of arguments, initializes the elements of the array instance
with the given argument values, and
uses the newly created array instance as the actual argument.
Except for allowing a variable number of arguments in an invocation, a
parameter array is precisely equivalent to
a value parameter (§17.5.1.1) of the same type.
[Example: The example
using System;
class Test
{
static void F(params int[] args) {
Console.Write("Array contains {0} elements:", args.Length);
foreach (int i in args)
Console.Write(" {0}", i);
Console.WriteLine();
}
static void Main() {
int[] arr = {1, 2, 3};
F(arr);
F(10, 20, 30, 40);
F();
}
}
produces the output
Array contains 3 elements: 1 2 3
Array contains 4 elements: 10 20 30 40
Array contains 0 elements:
The first invocation of F simply passes the array a as a value parameter.
The second invocation of F
automatically creates a four-element int[] with the given element values
and passes that array instance as a
value parameter. Likewise, the third invocation of F creates a zero-element
int[] and passes that instance as a
value parameter. The second and third invocations are precisely equivalent
to writing:
F(new int[] {10, 20, 30, 40});
F(new int[] {});
end example]
When performing overload resolution, a method with a parameter array may be
applicable either in its normal
form or in its expanded form (§14.4.2.1). The expanded form of a method is
available only if the normal form of
the method is not applicable and only if a method with the same signature
as the expanded form is not already
declared in the same type.
[Example: The example
C# LANGUAGE SPECIFICATION
232
using System;
class Test
{
static void F(params object[] a) {
Console.WriteLine("F(object[])");
}
static void F() {
Console.WriteLine("F()");
}
static void F(object a0, object a1) {
Console.WriteLine("F(object,object)");
}
static void Main() {
F();
F(1);
F(1, 2);
F(1, 2, 3);
F(1, 2, 3, 4);
}
}
produces the output
F();
F(object[]);
F(object,object);
F(object[]);
F(object[]);
In the example, two of the possible expanded forms of the method with a
parameter array are already included in
the class as regular methods. These expanded forms are therefore not
considered when performing overload
resolution, and the first and third method invocations thus select the
regular methods. When a class declares a
method with a parameter array, it is not uncommon to also include some of
the expanded forms as regular
methods. By doing so it is possible to avoid the allocation of an array
instance that occurs when an expanded
form of a method with a parameter array is invoked. end example]
When the type of a parameter array is object[], a potential ambiguity
arises between the normal form of the
method and the expended form for a single object parameter. The reason for
the ambiguity is that an object[]
is itself implicitly convertible to type object. The ambiguity presents no
problem, however, since it can be
resolved by inserting a cast if needed.
[Example: The example
using System;
class Test
{
static void F(params object[] args) {
foreach (object o in args) {
Console.Write(o.GetType().FullName);
Console.Write(" ");
}
Console.WriteLine();
}
static void Main() {
object[] a = {1, "Hello", 123.456};
object o = a;
F(a);
F((object)a);
F(o);
F((object[])o);
}
}
produces the output
Chapter 17 Classes
233
System.Int32 System.String System.Double
System.Object[]
System.Object[]
System.Int32 System.String System.Double
In the first and last invocations of F, the normal form of F is applicable
because an implicit conversion exists
from the argument type to the parameter type (both are of type object[]).
Thus, overload resolution selects the
normal form of F, and the argument is passed as a regular value parameter.
In the second and third invocations,
the normal form of F is not applicable because no implicit conversion
exists from the argument type to the
parameter type (type object cannot be implicitly converted to type
object[]). However, the expanded form of
F is applicable, so it is selected by overload resolution. As a result, a
one-element object[] is created by the
invocation, and the single element of the array is initialized with the
given argument value (which itself is a
reference to an object[]). end example]