In the following example, the method myMethod
has a single parameter named data
, of type int
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static void myMethod(int data)
{
data = data + 1; // Increment data by 1
Console.WriteLine(data); // Write data to screen
}
static void Main(string[] args)
{
myMethod(18);
Console.ReadLine();
}
}
}
Output:
We can control how parameters are passed with the ref
and out
modifiers.
The following table lists the features of ref
and out
modifiers.
Modifier | Item | Variable must be definitely assigned |
---|---|---|
(None) | Value | Going in |
ref | Reference | Going in |
out | Reference | Going out |
By default, arguments in C# are passed by value. Passing by value means a copy of the value is created when passed to the method.
Example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static void myMethod(int data)
{
data = data + 1; // Increment data by 1
Console.WriteLine(data); // Write data to screen
}
static void Main(string[] args)
{
int x = 18;
myMethod(x); // Make a copy of x
Console.WriteLine(x); // x will still be 18
Console.ReadLine();
}
}
}
Output:
Assigning data
a new value does not change the contents of x
.
Passing a reference-type argument by value copies the reference, not the object.
In the following example, myMethod
sees the same StringBuilder
object that Main
instantiated, but has an independent reference to it.
sb
and myMethodSB
are two different variables that reference the same StringBuilder
object:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static void myMethod(StringBuilder myMethodSB)
{
myMethodSB.Append("test");
myMethodSB = null;
}
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
myMethod(sb);
Console.WriteLine(sb.ToString()); // test
Console.ReadLine();
}
}
}
Output:
myMethodSB
is a copy of a reference, setting it to null
doesn't make sb
null.
To pass by reference, C# provides the ref
parameter modifier.
In the following example, p
and x
refer to the same memory locations:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static void myMethod(ref int p)
{
p = p + 1; // Increment p by 1
Console.WriteLine(p); // Write p to screen
}
static void Main(string[] args)
{
int x = 8;
myMethod(ref x); // Ask myMethod to deal directly with x
Console.WriteLine(x); // x is now 9
Console.ReadLine();
}
}
}
Output:
Assigning p
a new value changes the x
.
ref
modifier is required both when writing and when calling the method.
The following code shows how to use ref
modifier to create a swap method:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static void Swap(ref string a, ref string b)
{
string temp = a;
a = b;
b = temp;
}
static void Main(string[] args)
{
string x = "A";
string y = "B";
Swap(ref x, ref y);
Console.WriteLine(x);
Console.WriteLine(y);
Console.ReadLine();
}
}
}
Output:
A parameter can be passed by reference or by value, regardless of whether the parameter type is a reference type or a value type.
An out argument is like a ref
argument, except it:
The out
modifier is used to get multiple return values from a method.
Example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static void ToWords(string name, out string firstNames, out string lastName)
{
int i = name.LastIndexOf(' ');
firstNames = name.Substring(0, i);
lastName = name.Substring(i + 1);
}
static void Main(string[] args)
{
string a, b;
ToWords("this is a test", out a, out b);
Console.WriteLine(a);
Console.WriteLine(b);
Console.ReadLine();
}
}
}
Output:
Like a ref
parameter, an out
parameter is passed by reference.
The params
parameter modifier is used on the last parameter of a method so that the method accepts any number of parameters of a particular type.
The parameter type must be declared as an array.
Example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static int Sum(params int[] ints)
{
int sum = 0;
for (int i = 0; i < ints.Length; i++)
{
sum += ints[i]; // Increase sum by ints[i]
}
return sum;
}
static void Main(string[] args)
{
int total = Sum(1, 2, 3, 4);
Console.WriteLine("Total = "+total);
Console.ReadLine();
}
}
}
Output:
We can also supply a params
argument as an ordinary array.
int total = Sum (new int[] { 1, 2, 3, 4 } );
C# methods
, constructors
, and indexers
can declare optional parameters.
A parameter is optional if it specifies a default value in its declaration:
void myMethod (int x = 23) {
Console.WriteLine (x);
}
Optional parameters may be omitted when calling the method:
myMethod(); // 23
The default argument of 23 is actually passed to the optional parameter x
.
The preceding call to myMethod
is semantically identical to:
myMethod (23);
Optional parameters cannot be marked with ref
or out
.
The default value of an optional parameter must be a constant expression, or a parameter less constructor of a value type.
Mandatory parameters must occur before optional parameters in both the method declaration and the method call.
In the following example, the explicit value of 1 is passed to x
, and the default value of 0 is passed to y
:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static void myMethod(int x = 0, int y = 0)
{
Console.WriteLine(x + ", " + y);
}
static void Main(string[] args)
{
myMethod(1);
Console.ReadLine();
}
}
}
Output:
To pass a default value to x
and an explicit value to y
we must combine optional parameters with named arguments.
We can identify an argument by name.
For example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static void myMethod(int x, int y)
{
Console.WriteLine(x + ", " + y);
}
static void Main(string[] args)
{
myMethod(x: 1, y: 2);
Console.ReadLine();
}
}
}
Output:
Named arguments can occur in any order.
The following calls to myMethod
are semantically identical:
myMethod (x:1, y:2);
myMethod (y:2, x:1);
We can mix named and positional parameters:
myMethod (1, y:2);
Positional parameters must come before named arguments.
So we couldn't call myMethod
like this:
myMethod (x:1, 2); // Compile-time error
Named arguments are useful with optional parameters.
For instance, consider the following method:
void myMethod (int a = 0, int b = 0, int c = 0, int d = 0) { ... }
We can call this supplying only a value for d
as follows:
myMethod (d:3);