メソッドの定義で引数に ref を付けるとその引数は参照渡しになります。
引数になにも付けていないとその引数は値渡しになります。
値渡しによるパラメーターのやりとりは呼び出し元の変数に影響がありません。
メソッド内で引数に値を代入しても呼び出し元の変数の中身は変わらないということになります。
参照渡しはメソッドにパラメータとして渡す変数を入力にも出力にもしたいときに使います。
メソッド内で引数に値を代入すると呼び出し元の変数の中身もその値になるということなります。
ややこしいですが、変数で出てきた値型、参照型とはまた違う用語です。
値型、参照型はその型のデータの格納方法で、
値渡し、参照渡しはメソッドの引数へのパラメータの渡し方です。
なのでメソッドの引数には、
- 値型の値渡し
- 値型の参照渡し
- 参照型の値渡し
- 参照型の参照渡し
の4パターンがあります。
値渡しとは?
普通にメソッドの定義をすると引数は値渡しになります。
値渡しは引数にメソッドを呼び出すときに指定された値(変数の中身)をコピーして渡す方法です。
メソッド内ではコピーされた値が使われるため、コピー元の変数には影響がありません。
値型の値渡し
下のコードは値型の値渡しの例です。
class Program
{
static int Method(int a)
{
a = a * 2;
return a;
}
public static void Main()
{
int a = 10;
int result = Method(a);
System.Console.WriteLine(a);
System.Console.WriteLine(result);
}
}
出力結果はこんな感じです。
10
20
変数aの値をコピーしているので、メソッド内で引数aの値を変更していますが元の変数aには影響がありません。
参照型の値渡し
同じように参照型の値渡しの場合も元の変数の中身に影響はありません。
class Program
{
static void Method(SampleClass a)
{
System.Console.WriteLine($"引数aのx = {a.x}");
a = new SampleClass() { x = 20 };
System.Console.WriteLine($"引数aのx = {a.x}");
}
public static void Main()
{
SampleClass a = new SampleClass() { x = 10 };
System.Console.WriteLine($"Sample.xの初期値 = {a.x}");
Method(a);
System.Console.WriteLine($"メソッド実行後の変数aのx = {a.x}");
}
}
class SampleClass
{
public int x;
}
処理結果はこんな感じです。
Sample.xの初期値 = 10
引数aのx = 10
引数aのx = 20
メソッド実行後の変数aのx = 10
引数aにコピーされる値はこんな感じでインスタンスへの参照情報になります。
メソッドの処理の中で引数aにnewをするとこんな感じになります。
上の図のように引数aにnewをすると新たにクラスインスタンスが作成され、その参照情報が代入されます。
この状態でxに20を代入したとしても引数aはコピー元の変数aと指しているインスタンスが違うので影響はありません。
ちなみに、メソッド内でクラスメンバー x の値を変更すると呼び出し元のクラスメンバー x も変更されます。
class Program
{
static void Method(SampleClass a)
{
System.Console.WriteLine($"引数aのx = {a.x}");
a.x = 20;
System.Console.WriteLine($"引数aのx = {a.x}");
}
public static void Main()
{
SampleClass a = new SampleClass() { x = 10 };
System.Console.WriteLine($"Sample.xの初期値 = {a.x}");
Method(a);
System.Console.WriteLine($"メソッド実行後の変数aのx = {a.x}");
}
}
class SampleClass
{
public int x;
}
Sample.xの初期値 = 10
引数aのx = 10
引数aのx = 20
メソッド実行後の変数aのx = 20
サンプルコード6行目のメソッド内でクラスメンバーxに20を代入すると、呼び出し元の変数a.x の値も変わっています。
これは、参照型の値渡しはコピーされるのは変数の中身(この場合はSampleクラスのインスタンスへの参照情報)なので、クラスインスタンスのメンバーへのアクセスは直接行われるためです。
参照渡しとは?
メソッドを定義するときに引数に ref キーワードを付けると参照渡しになります。参照渡しは引数にメソッドを呼び出すときに指定された変数への参照情報を渡します。
参照渡しの場合は、メソッド内の処理によってパラメータに指定した変数の値が変更されます。
また参照渡しの場合、呼び出す側も ref を付ける必要があります。
実は out キーワードを使った引数を出力として使う方法も参照渡しになります。
outはメソッド内での初期化を強制する参照渡しです。
値型の参照渡し
class Program
{
static void Method(ref int a)
{
System.Console.WriteLine($"引数a = {a}");
a = 20;
System.Console.WriteLine($"引数a = {a}");
}
public static void Main()
{
int a = 10;
System.Console.WriteLine($"変数aの初期値 = {a}");
// 参照渡しの場合、呼び出す方にも ref を付ける必要がある
Method(ref a);
System.Console.WriteLine($"メソッド実行後の変数a = {a}");
}
}
参照渡しの場合メソッドを呼び出す側も ref を付けます。
Method(ref a);
出力結果はこんな感じです。
変数aの初期値 = 10
引数a = 10
引数a = 20
メソッド実行後の変数a = 20
値渡しと違って今度は呼び出し側の変数aの値も変わりました。
引数に渡される参照情報はこんな感じイメージです。
メソッド内の処理で行われるとこんな感じになります。
参照型の参照渡し
こちらもメソッドの呼び出しで指定した変数の中身が変更されます。
class Program
{
static void Method(ref SampleClass a)
{
System.Console.WriteLine($"引数aのx = {a.x}");
a = new SampleClass() { x = 20 };
System.Console.WriteLine($"引数aのx = {a.x}");
}
public static void Main()
{
SampleClass a = new SampleClass() { x = 10 };
System.Console.WriteLine($"変数aのxの初期値 = {a.x}");
// 参照渡しの場合、呼び出す方にも ref を付ける必要がある
Method(ref a);
System.Console.WriteLine($"メソッド実行後の変数aのx = {a.x}");
}
}
class SampleClass
{
public int x;
}
出力結果はこんな感じです。
変数aのxの初期値 = 10
引数aのx = 10
引数aのx = 20
メソッド実行後の変数aのx = 20
参照型の場合も変数aへの参照情報が引数にわたされます。
メソッド内で新しいクラスのインスタンスが作成され、その参照情報が引数aが指し示す変数aに代入されます。そのためメソッド実行後の x の値が20になっています。
参照型の参照渡しの場合も引数に渡されるのは変数aへの参照情報です。
この状態で新しいインスタンスへの参照情報を引数aに代入すると、引数aの参照先の変数aに新しいインスタンスへの参照情報が代入されます。
C# 記事まとめページに戻る(他のサンプルコードもこちら)
コメント