C#のgoto文とは?使い方・危険性・使ってもよいケースを初心者向けに解説

はじめに

C#には、処理の流れを指定した場所へ移動させるためのgoto文があります。

goto文は、うまく使えば複雑なループから抜ける処理などを簡潔に書ける場合があります。一方で、使い方を間違えるとコードの流れが追いにくくなり、バグの原因にもなりやすい構文です。

そのため、C#を学び始めたばかりの人にとっては、

「C#のgoto文は何のためにあるのか」
「goto文は使ってもよいのか」
「危険と言われる理由は何か」
「goto文を使わない書き方はあるのか」

といった疑問が出てきやすいでしょう。

この記事では、C#のgoto文について、基本構文、サンプルコード、危険性、使ってもよいケース、代替方法まで初心者向けにわかりやすく解説します。

1. C#のgoto文とは?

C#のgoto文は、プログラムの処理を指定した場所へジャンプさせるための文です。

通常、プログラムは上から下へ順番に実行されます。しかし、goto文を使うと、あらかじめ定義したラベルやswitch文の特定のcaseへ処理を移動できます。

ただし、goto文は便利そうに見える一方で、コードの流れを複雑にしやすい構文でもあります。そのため、C#では使えるものの、日常的に多用するべきものではありません。

1-1. goto文は指定したラベルへ処理をジャンプさせる文

goto文は、指定したラベルへ処理をジャンプさせます。

たとえば、次のようなイメージです。

C#
goto End;

Console.WriteLine("この行は実行されません");

End:
Console.WriteLine("終了処理です");

このコードでは、goto End;によってEnd:というラベルまで処理がジャンプします。

そのため、途中にあるConsole.WriteLine("この行は実行されません");は実行されません。

このように、goto文を使うと処理の流れを強制的に変えることができます。

1-2. C#で使えるgoto文の主な種類

C#で使えるgoto文には、主に次のような種類があります。

C#
goto ラベル名;

指定したラベルへジャンプする基本的な書き方です。

C#
goto case ;

switch文の中で、指定したcaseへ処理を移動する書き方です。

C#
goto default;

switch文の中で、defaultの処理へ移動する書き方です。

一般的に「goto文」と聞いたときにイメージされるのは、goto ラベル名;の形式です。ただし、C#ではswitch文の中でgoto casegoto defaultを使うこともあります。

1-3. 初心者がgoto文を検索する理由とこの記事でわかること

C#初心者がgoto文について調べる理由としては、次のようなものがあります。

「サンプルコードにgotoが出てきた」
「多重ループから抜ける方法を探している」
switch文でgoto caseを見かけた」
「goto文は使ってはいけないと聞いた」
「なぜ危険なのかを知りたい」

この記事では、こうした疑問に答えるために、C#のgoto文の基本から実用上の注意点まで順番に解説します。

特に、初心者が理解しておきたいポイントは次の3つです。

1つ目は、goto文の基本的な書き方です。

2つ目は、goto文が危険・非推奨と言われる理由です。

3つ目は、goto文を使わずに書き換える方法です。

goto文は、C#で必ず使いこなさなければならない構文ではありません。しかし、意味を理解しておくことで、既存コードを読んだり、特殊なケースで適切に判断したりできるようになります。

2. C#のgoto文の基本構文

C#のgoto文を理解するには、まず「ラベル」と「ジャンプ」の考え方を押さえる必要があります。

ラベルとは、プログラム内の特定の位置に名前を付けたものです。goto文は、そのラベル名を指定して処理を移動します。

2-1. ラベルを定義する書き方

C#でラベルを定義するには、ラベル名の後ろにコロンを付けます。

C#
ラベル名:

たとえば、次のように書きます。

C#
End:
Console.WriteLine("終了しました");

この場合、End:がラベルです。

ラベル名は自由に付けられますが、処理内容がわかる名前にすることが大切です。

悪い例は次のような名前です。

C#
A:
B:
Label1:

これでは、どのような処理にジャンプするのかがわかりにくくなります。

わかりやすい例は次のような名前です。

C#
Error:
Exit:
Retry:
EndProcess:

ラベル名を見るだけで、エラー処理、終了処理、再試行処理など、目的が想像しやすくなります。

2-2. goto ラベル名でジャンプする書き方

ラベルへジャンプするには、gotoの後ろにラベル名を書きます。

C#
goto ラベル名;

たとえば、次のように使います。

C#
goto End;

End:
Console.WriteLine("終了処理です");

この場合、goto End;が実行されると、処理はEnd:の位置へ移動します。

goto文の末尾にはセミコロンが必要です。一方、ラベルの末尾にはコロンを付けます。

C#
goto End; // セミコロン

End: // コロン

この違いは初心者が間違えやすいポイントです。

2-3. goto文の基本的な実行の流れ

goto文の基本的な流れは、次のようになります。

C#
using System;

class Program
{
static void Main()
{
Console.WriteLine("開始");

goto End;

Console.WriteLine("途中の処理");

End:
Console.WriteLine("終了");
}
}

実行結果は次のようになります。

開始
終了

goto End;によって、End:まで処理がジャンプするため、Console.WriteLine("途中の処理");は実行されません。

このように、goto文は処理を飛ばすことができます。

ただし、処理を飛ばせるということは、コードを読む人が「次にどこが実行されるのか」を追いにくくなるということでもあります。

2-4. goto文でジャンプできないケース

C#のgoto文は、どこへでも自由にジャンプできるわけではありません。

たとえば、別のメソッドへジャンプすることはできません。

C#
static void Main()
{
goto OtherMethodLabel; // これはできない
}

static void OtherMethod()
{
OtherMethodLabel:
Console.WriteLine("別メソッドのラベル");
}

goto文でジャンプできるのは、基本的に同じメソッド内のラベルです。

また、スコープの外から内側へ無理にジャンプするような書き方もできません。

C#
goto Inside;

if (true)
{
Inside:
Console.WriteLine("内側のブロック");
}

このようなコードは、ブロックの外から内側のラベルへジャンプしようとしているため、コンパイルエラーになります。

さらに、trycatchfinallyが関係する場所では、ジャンプできる位置に制限があります。特にfinallyブロックの扱いには注意が必要です。

つまり、C#のgoto文は強力ですが、完全に自由なジャンプ命令ではありません。安全性を保つために、言語仕様上の制限が設けられています。

3. C#のgoto文の使い方をサンプルコードで解説

ここからは、C#のgoto文の使い方をサンプルコードで確認していきます。

基本的な使い方から、条件分岐、ループ、switch文でのgoto casegoto defaultまで順番に見ていきましょう。

3-1. 基本的なgoto文のサンプル

まずは、もっとも基本的なgoto文の例です。

C#
using System;

class Program
{
static void Main()
{
Console.WriteLine("処理を開始します");

goto Finish;

Console.WriteLine("この処理は実行されません");

Finish:
Console.WriteLine("処理を終了します");
}
}

実行結果は次のとおりです。

処理を開始します
処理を終了します

goto Finish;が実行されると、処理はFinish:ラベルに移動します。

そのため、途中にあるConsole.WriteLine("この処理は実行されません");はスキップされます。

このように、goto文を使うと任意のラベルへ処理を移動できます。

ただし、この例のような単純な処理であれば、わざわざgoto文を使う必要はありません。通常はif文やreturn文などで書いた方が自然です。

3-2. 条件分岐とgoto文を組み合わせる例

次に、条件によって指定したラベルへジャンプする例を見てみましょう。

C#
using System;

class Program
{
static void Main()
{
int score = 40;

if (score < 60)
{
goto Failed;
}

Console.WriteLine("合格です");
goto End;

Failed:
Console.WriteLine("不合格です");

End:
Console.WriteLine("判定を終了します");
}
}

実行結果は次のようになります。

不合格です
判定を終了します

scoreが60未満なので、goto Failed;が実行され、Failed:ラベルに処理が移動します。

このコードはgoto文の動きを理解するにはわかりやすい例です。

しかし、実際には次のようにif文だけで書いた方が読みやすくなります。

C#
using System;

class Program
{
static void Main()
{
int score = 40;

if (score < 60)
{
Console.WriteLine("不合格です");
}
else
{
Console.WriteLine("合格です");
}

Console.WriteLine("判定を終了します");
}
}

このように、条件分岐のためだけにgoto文を使う必要はほとんどありません。

3-3. ループ処理から抜けるためにgoto文を使う例

goto文が使われることがある場面の1つに、多重ループから一気に抜けたい場合があります。

たとえば、次のコードでは、2重ループの中で特定の値を見つけたら、外側のループも含めて一気に抜けています。

C#
using System;

class Program
{
static void Main()
{
int[,] numbers =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};

int target = 5;

for (int i = 0; i < numbers.GetLength(0); i++)
{
for (int j = 0; j < numbers.GetLength(1); j++)
{
if (numbers[i, j] == target)
{
Console.WriteLine($"見つかりました: i={i}, j={j}");
goto Found;
}
}
}

Console.WriteLine("見つかりませんでした");

Found:
Console.WriteLine("検索を終了します");
}
}

実行結果は次のようになります。

見つかりました: i=1, j=1
検索を終了します

通常のbreak文は、内側のループだけを抜けます。

C#
break;

そのため、2重ループや3重ループから一気に抜けたい場合には、goto文が選択肢になることがあります。

ただし、このような場合でも、メソッドに分割してreturnで抜ける方が読みやすいことが多いです。

3-4. switch文でgoto caseを使う例

C#では、switch文の中でgoto caseを使うことができます。

goto caseは、指定したcaseの処理へ移動するための構文です。

C#
using System;

class Program
{
static void Main()
{
int number = 1;

switch (number)
{
case 1:
Console.WriteLine("1の処理です");
goto case 2;

case 2:
Console.WriteLine("2の処理です");
break;

default:
Console.WriteLine("その他の処理です");
break;
}
}
}

実行結果は次のようになります。

1の処理です
2の処理です

number1なので、まずcase 1が実行されます。

その後、goto case 2;によってcase 2の処理へ移動します。

C#のswitch文では、C言語のように何も書かずに次のcaseへ処理が流れる「フォールスルー」は基本的にできません。そのため、別のcaseの処理を明示的に実行したい場合にgoto caseを使います。

3-5. switch文でgoto defaultを使う例

switch文では、goto defaultを使ってdefaultの処理へ移動することもできます。

C#
using System;

class Program
{
static void Main()
{
string role = "guest";

switch (role)
{
case "admin":
Console.WriteLine("管理者です");
break;

case "guest":
Console.WriteLine("ゲストユーザーです");
goto default;

default:
Console.WriteLine("基本権限を適用します");
break;
}
}
}

実行結果は次のとおりです。

ゲストユーザーです
基本権限を適用します

この例では、roleguestなので、まずcase "guest"の処理が実行されます。

その後、goto default;によってdefaultの処理へ移動し、基本権限を適用しています。

goto defaultは、複数の条件で共通の処理を実行したい場合に使えます。

ただし、使いすぎるとswitch文の流れがわかりにくくなるため、本当に読みやすくなる場合だけ使うようにしましょう。

4. C#のgoto文が危険・非推奨と言われる理由

C#のgoto文は言語として用意されている構文ですが、一般的には多用しない方がよいとされています。

理由は、goto文が処理の流れをわかりにくくし、保守性を下げやすいからです。

ここでは、goto文が危険・非推奨と言われる主な理由を解説します。

4-1. 処理の流れが追いにくくなる

通常のC#コードは、上から下へ順番に読み進めれば処理の流れを理解できます。

しかし、goto文があると、処理が突然別の場所へ移動します。

C#
Console.WriteLine("A");

goto C;

Console.WriteLine("B");

C:
Console.WriteLine("C");

この程度の短いコードであれば問題ないかもしれません。

しかし、実際のプログラムでは、コードが何十行、何百行にもなることがあります。その中でgoto文が複数使われていると、次にどこが実行されるのかを追うのが難しくなります。

コードは書く時間よりも読む時間の方が長くなりがちです。

そのため、処理の流れが追いにくいコードは、後から修正する人にとって大きな負担になります。

4-2. スパゲッティコードになりやすい

goto文を多用すると、処理の流れがあちこちに飛ぶコードになりやすくなります。

このようなコードは「スパゲッティコード」と呼ばれます。

スパゲッティコードとは、処理の流れが複雑に絡み合っていて、どこからどこへ進むのかがわかりにくいコードのことです。

たとえば、次のようなコードは読みづらくなりやすいです。

C#
Start:
Console.WriteLine("開始");

goto Check;

Error:
Console.WriteLine("エラー処理");
goto End;

Check:
Console.WriteLine("チェック処理");
goto Error;

End:
Console.WriteLine("終了");

この例は短いのでまだ追えますが、同じようなジャンプが大きなプログラム内で何度も出てくると、全体の流れを把握するのが難しくなります。

goto文そのものが必ず悪いわけではありません。しかし、無計画に使うとスパゲッティコードを生みやすい点には注意が必要です。

4-3. バグの原因を見つけにくくなる

goto文が多いコードでは、バグが起きたときに原因を見つけにくくなります。

なぜなら、処理がどの経路を通ってその場所に到達したのかを確認する必要があるからです。

たとえば、変数の値がおかしい場合、通常であれば上から順番に処理を追えば原因を探せます。

しかし、goto文によって処理が何度もジャンプしていると、

「この変数はどこで変更されたのか」
「この処理は本当に実行されたのか」
「このラベルにはどこからジャンプしてくるのか」

といった確認が必要になります。

その結果、デバッグに時間がかかります。

特に初心者の場合、goto文を使ったコードをデバッグするのは難しくなりやすいです。

4-4. 保守性・可読性が下がる

保守性とは、後からコードを修正しやすいかどうかを表す考え方です。

可読性とは、コードの読みやすさです。

goto文を多用すると、保守性と可読性の両方が下がりやすくなります。

たとえば、次のような問題が起きます。

処理の開始地点と終了地点がわかりにくくなる。

条件分岐の意味が読み取りにくくなる。

ラベル名が増えて全体の構造が複雑になる。

修正したときに別のジャンプ先へ影響が出る。

チーム開発では、自分以外の人もコードを読みます。そのため、自分だけが理解できるコードでは不十分です。

goto文を使う場合は、他の人が読んでもすぐに理解できるかを考える必要があります。

4-5. 初心者がgoto文を多用してはいけない理由

初心者がgoto文を多用してはいけない大きな理由は、基本的な制御構文の理解が深まりにくくなるからです。

C#には、処理の流れを制御するための構文がたくさんあります。

C#
if
else
switch
for
while
do while
break
continue
return
try-catch

これらを正しく使えば、多くの処理はgoto文なしで書けます。

初心者のうちからgoto文に頼ってしまうと、本来if文やループで整理できる処理まで、ジャンプで解決しようとしてしまいます。

その結果、読みづらいコードを書く癖がついてしまう可能性があります。

まずは、if文、for文、while文、break文、continue文、return文をしっかり使えるようになることが大切です。

goto文は、基本を理解したうえで、必要な場面だけ慎重に使う構文だと考えましょう。

5. goto文を使わずに書き換える方法

goto文を見かけたときは、まず「他の構文で書き換えられないか」を考えることが大切です。

C#では、多くの場合、goto文を使わなくても同じ処理を書けます。

ここでは、if文、ループ、break文、continue文、return文、メソッド分割による書き換え方法を紹介します。

5-1. if文で書き換える

条件によって処理を分けるだけなら、goto文ではなくif文を使うのが基本です。

goto文を使った例です。

C#
int score = 80;

if (score >= 60)
{
goto Passed;
}

Console.WriteLine("不合格です");
goto End;

Passed:
Console.WriteLine("合格です");

End:
Console.WriteLine("判定終了");

このコードは、次のようにif文で書き換えられます。

C#
int score = 80;

if (score >= 60)
{
Console.WriteLine("合格です");
}
else
{
Console.WriteLine("不合格です");
}

Console.WriteLine("判定終了");

こちらの方が、処理の流れが自然で読みやすくなります。

条件によって処理を分ける場合は、まずif文やelse文で書けないかを考えましょう。

5-2. while文・for文で書き換える

繰り返し処理をgoto文で書くこともできますが、通常はwhile文やfor文を使います。

goto文を使った例です。

C#
int count = 0;

Loop:
Console.WriteLine(count);
count++;

if (count < 5)
{
goto Loop;
}

このコードは、次のようにwhile文で書き換えられます。

C#
int count = 0;

while (count < 5)
{
Console.WriteLine(count);
count++;
}

また、回数が決まっている場合はfor文が向いています。

C#
for (int count = 0; count < 5; count++)
{
Console.WriteLine(count);
}

繰り返し処理は、goto文よりもwhile文やfor文を使った方が意図が伝わりやすくなります。

5-3. break文で書き換える

ループを途中で抜けたい場合は、break文を使います。

goto文を使った例です。

C#
for (int i = 0; i < 10; i++)
{
if (i == 5)
{
goto EndLoop;
}

Console.WriteLine(i);
}

EndLoop:
Console.WriteLine("ループ終了");

このコードは、次のようにbreak文で書き換えられます。

C#
for (int i = 0; i < 10; i++)
{
if (i == 5)
{
break;
}

Console.WriteLine(i);
}

Console.WriteLine("ループ終了");

break文は、現在のループを抜けるための構文です。

単一のループから抜けるだけであれば、goto文ではなくbreak文を使いましょう。

5-4. continue文で書き換える

ループ内で、現在の処理だけをスキップして次の繰り返しに進みたい場合は、continue文を使います。

goto文を使った例です。

C#
for (int i = 0; i < 5; i++)
{
if (i == 2)
{
goto ContinueLoop;
}

Console.WriteLine(i);

ContinueLoop:
;
}

このコードは、次のようにcontinue文で書き換えられます。

C#
for (int i = 0; i < 5; i++)
{
if (i == 2)
{
continue;
}

Console.WriteLine(i);
}

実行結果は次のようになります。

0
1
3
4

i2のときだけ、Console.WriteLine(i);がスキップされます。

このような処理は、goto文よりもcontinue文を使った方が明確です。

5-5. return文で書き換える

メソッドの処理を途中で終了したい場合は、return文を使います。

goto文を使った例です。

C#
static void CheckAge(int age)
{
if (age < 0)
{
goto Error;
}

Console.WriteLine("年齢は正常です");
goto End;

Error:
Console.WriteLine("年齢が不正です");

End:
Console.WriteLine("処理終了");
}

このコードは、次のようにreturn文で書き換えられます。

C#
static void CheckAge(int age)
{
if (age < 0)
{
Console.WriteLine("年齢が不正です");
Console.WriteLine("処理終了");
return;
}

Console.WriteLine("年齢は正常です");
Console.WriteLine("処理終了");
}

さらに、共通の終了処理を整理すると次のようにも書けます。

C#
static void CheckAge(int age)
{
if (age < 0)
{
Console.WriteLine("年齢が不正です");
return;
}

Console.WriteLine("年齢は正常です");
}

メソッドを途中で終了したいだけなら、goto文よりもreturn文の方が自然です。

5-6. メソッド分割で処理を整理する

多重ループや複雑な条件分岐では、goto文を使うよりもメソッド分割をした方が読みやすくなることがあります。

たとえば、2重ループから抜けたい処理を考えます。

C#
static void Search()
{
int[,] numbers =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};

int target = 5;

for (int i = 0; i < numbers.GetLength(0); i++)
{
for (int j = 0; j < numbers.GetLength(1); j++)
{
if (numbers[i, j] == target)
{
Console.WriteLine("見つかりました");
goto EndSearch;
}
}
}

Console.WriteLine("見つかりませんでした");

EndSearch:
Console.WriteLine("検索終了");
}

このコードは、メソッドを分けてreturnを使うと整理できます。

C#
static void Search()
{
int[,] numbers =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};

int target = 5;

if (Exists(numbers, target))
{
Console.WriteLine("見つかりました");
}
else
{
Console.WriteLine("見つかりませんでした");
}

Console.WriteLine("検索終了");
}

static bool Exists(int[,] numbers, int target)
{
for (int i = 0; i < numbers.GetLength(0); i++)
{
for (int j = 0; j < numbers.GetLength(1); j++)
{
if (numbers[i, j] == target)
{
return true;
}
}
}

return false;
}

メソッド分割をすると、検索処理と表示処理が分かれて読みやすくなります。

複雑な処理をgoto文でつなぐのではなく、処理のまとまりごとにメソッドへ分けることを意識しましょう。

6. C#でgoto文を使ってもよいケース

goto文は危険・非推奨と言われることが多いですが、絶対に使ってはいけないわけではありません。

C#の言語仕様として存在している以上、使いどころはあります。

重要なのは、goto文を使うことで本当にコードが読みやすくなるかを判断することです。

6-1. 多重ループから一気に抜けたい場合

goto文が比較的使われやすいケースの1つが、多重ループから一気に抜けたい場合です。

たとえば、次のような2重ループがあります。

C#
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (i * j > 30)
{
goto ExitLoop;
}
}
}

ExitLoop:
Console.WriteLine("ループを抜けました");

break文だけでは、内側のループしか抜けられません。

C#
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (i * j > 30)
{
break;
}
}
}

この場合、breakで抜けられるのは内側のfor文だけです。

外側のループも含めて一気に抜けたい場合、goto文を使うと簡潔に書けることがあります。

ただし、メソッドに切り出してreturnする方法も検討しましょう。

C#
static bool HasLargeValue()
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (i * j > 30)
{
return true;
}
}
}

return false;
}

多重ループから抜けたい場合でも、まずはreturnやメソッド分割で整理できないかを考えるのがおすすめです。

6-2. switch文で処理を明示的に共有したい場合

C#のswitch文では、goto caseを使って別のcaseの処理を明示的に実行できます。

C#
int rank = 1;

switch (rank)
{
case 1:
Console.WriteLine("特別賞を付与します");
goto case 2;

case 2:
Console.WriteLine("通常賞を付与します");
break;

default:
Console.WriteLine("賞はありません");
break;
}

この例では、rank1の場合に、特別賞と通常賞の両方を付与しています。

goto caseを使うことで、「case 1の後にcase 2の処理も実行する」という意図を明示できます。

ただし、共通処理が多い場合は、メソッドに分けた方が読みやすいこともあります。

C#
void GiveNormalReward()
{
Console.WriteLine("通常賞を付与します");
}

goto caseを使うか、メソッドに分けるかは、コードの読みやすさを基準に判断しましょう。

6-3. 例外的にコードが読みやすくなる場合

まれに、goto文を使った方がコードが読みやすくなる場合があります。

たとえば、複雑な条件の途中で共通の終了処理へ移動したい場合です。

C#
if (!CheckA())
{
goto Error;
}

if (!CheckB())
{
goto Error;
}

if (!CheckC())
{
goto Error;
}

Console.WriteLine("すべて成功しました");
goto End;

Error:
Console.WriteLine("エラーが発生しました");

End:
Console.WriteLine("処理を終了します");

ただし、このようなコードも、実際にはreturnや例外処理、メソッド分割で書き換えられることが多いです。

C#
if (!CheckA() || !CheckB() || !CheckC())
{
Console.WriteLine("エラーが発生しました");
return;
}

Console.WriteLine("すべて成功しました");

goto文を使って読みやすくなるケースは限定的です。

「なんとなく便利だから使う」のではなく、「他の構文よりも明確に読みやすい」と判断できる場合だけ使いましょう。

6-4. goto文を使う前に確認すべき判断基準

goto文を使う前には、次の点を確認しましょう。

まず、if文で書けないかを考えます。

次に、break文やcontinue文で書けないかを確認します。

メソッドを分けてreturnできないかも検討します。

switch文であれば、goto caseよりも共通処理をメソッド化した方がよくないかを考えます。

そのうえで、goto文を使った方が明らかに読みやすい場合だけ採用します。

判断の基準は、「短く書けるか」ではなく「読みやすいか」です。

短く書けても、処理の流れがわかりにくくなるなら避けるべきです。

逆に、goto文を1つ使うことで多重ループの終了位置が明確になり、全体が読みやすくなるなら、選択肢として考えてもよいでしょう。

7. goto文を使うときの注意点

C#でgoto文を使う場合は、いくつかの注意点があります。

goto文は便利な反面、コードの見通しを悪くしやすいため、使う場合はルールを決めて慎重に扱う必要があります。

7-1. ラベル名は処理内容がわかる名前にする

ラベル名は、ジャンプ先の処理内容がわかる名前にしましょう。

悪い例です。

C#
goto A;

A:
Console.WriteLine("終了処理");

Aというラベル名では、何をする場所なのかわかりません。

良い例です。

C#
goto Exit;

Exit:
Console.WriteLine("終了処理");

このように、Exitという名前であれば、終了処理へ移動することがわかります。

エラー処理であればError、再試行であればRetry、終了処理であればExitEndProcessのように、目的が伝わる名前を付けましょう。

ラベル名がわかりやすいだけでも、goto文の読みづらさをある程度減らせます。

7-2. ジャンプ先を増やしすぎない

goto文を使う場合は、ジャンプ先を増やしすぎないことが大切です。

1つのメソッド内にラベルがいくつもあると、処理の流れが複雑になります。

C#
goto Step1;

Step1:
goto Step2;

Step2:
goto Step3;

Step3:
goto End;

End:
Console.WriteLine("終了");

このようなコードは、処理があちこちに飛んで読みづらくなります。

goto文を使う場合でも、ジャンプ先はできるだけ少なくしましょう。

特に、複数の場所から複数のラベルへジャンプするような構造は避けるべきです。

目安としては、1つの目的のために1つのラベルを使う程度にとどめるのが安全です。

7-3. メソッドをまたいだジャンプはできない

C#のgoto文では、メソッドをまたいだジャンプはできません。

たとえば、次のようなコードは書けません。

C#
static void Main()
{
goto Target;
}

static void Sample()
{
Target:
Console.WriteLine("ジャンプ先");
}

goto文でジャンプできるのは、同じメソッド内にあるラベルです。

別のメソッドのラベルへ移動することはできません。

別の処理を実行したい場合は、goto文ではなくメソッド呼び出しを使います。

C#
static void Main()
{
Sample();
}

static void Sample()
{
Console.WriteLine("別メソッドの処理");
}

メソッドをまたぐ処理の移動には、goto文ではなく、メソッド呼び出しやreturnを使いましょう。

7-4. try-catch-finally内での扱いに注意する

trycatchfinallyを使う処理では、goto文の扱いに注意が必要です。

特にfinallyブロックは、例外の有無にかかわらず実行される重要な処理を書く場所です。

たとえば、ファイルを閉じる処理やリソースを解放する処理などを書くことがあります。

C#
try
{
Console.WriteLine("tryの処理");
goto End;
}
finally
{
Console.WriteLine("finallyの処理");
}

End:
Console.WriteLine("終了");

このような場合、goto End;で外へ移動するときでも、finallyブロックは実行されます。

実行結果は次のようになります。

tryの処理
finallyの処理
終了

一方で、trycatchfinallyの内部へ外側から無理にジャンプするような書き方はできません。

try-catch-finallyは例外処理やリソース管理に関わる重要な構文です。

この中でgoto文を使うと処理の流れがわかりにくくなるため、できるだけ避けた方が安全です。

7-5. チーム開発ではコーディング規約を確認する

チーム開発では、goto文を使う前にコーディング規約を確認しましょう。

プロジェクトによっては、goto文の使用を禁止している場合があります。

また、完全に禁止されていなくても、特別な理由がある場合だけ使用を認めるルールになっていることもあります。

チーム開発では、自分が読みやすいと思うだけでは不十分です。

他のメンバーが読んでも理解しやすいか、レビューで説明できるか、保守しやすいかを考える必要があります。

goto文を使う場合は、なぜgoto文が必要なのかを説明できるようにしておきましょう。

説明できない場合は、if文、break文、continue文、return文、メソッド分割などで書き換えた方がよい可能性が高いです。

8. C#のgoto文に関するよくある質問

ここでは、C#のgoto文に関するよくある質問に答えます。

初心者が疑問に思いやすいポイントを整理しておきましょう。

8-1. C#でgoto文は使ってはいけないの?

C#でgoto文を使ってはいけないわけではありません。

C#には正式にgoto文が用意されており、goto ラベル名goto casegoto defaultといった書き方ができます。

ただし、一般的には多用しない方がよい構文です。

理由は、処理の流れが追いにくくなり、コードの可読性や保守性が下がりやすいからです。

特に初心者のうちは、goto文を使う前に、if文、for文、while文、break文、continue文、return文で書けないかを考えるのがおすすめです。

goto文は「禁止」ではなく「慎重に使うべき構文」と考えるとよいでしょう。

8-2. goto文とbreak文の違いは?

goto文とbreak文の違いは、移動先を指定できるかどうかです。

break文は、現在のループやswitch文を抜けるための構文です。

C#
for (int i = 0; i < 10; i++)
{
if (i == 5)
{
break;
}
}

この場合、i5になった時点でループを抜けます。

一方、goto文は指定したラベルへ処理をジャンプさせます。

C#
goto End;

End:
Console.WriteLine("終了");

break文は決められた範囲から抜けるための構文で、goto文は指定した場所へ移動するための構文です。

単純にループを抜けるだけなら、goto文ではなくbreak文を使いましょう。

8-3. goto文とcontinue文の違いは?

goto文とcontinue文の違いは、ループの次の繰り返しへ進むか、指定したラベルへジャンプするかです。

continue文は、現在のループ処理を途中でスキップし、次の繰り返しへ進みます。

C#
for (int i = 0; i < 5; i++)
{
if (i == 2)
{
continue;
}

Console.WriteLine(i);
}

このコードでは、i2のときだけ表示処理をスキップします。

一方、goto文は指定したラベルへ移動します。

C#
goto Skip;

Console.WriteLine("表示されません");

Skip:
Console.WriteLine("ここへ移動します");

ループ内で次の繰り返しへ進みたいだけなら、continue文を使うのが基本です。

goto文を使う必要はほとんどありません。

8-4. goto caseとは何?

goto caseとは、C#のswitch文の中で、指定したcaseへ処理を移動するための構文です。

C#
int value = 1;

switch (value)
{
case 1:
Console.WriteLine("case 1です");
goto case 2;

case 2:
Console.WriteLine("case 2です");
break;
}

このコードでは、case 1の処理を実行した後、goto case 2;によってcase 2の処理も実行されます。

実行結果は次のようになります。

case 1です
case 2です

C#のswitch文では、何も書かずに次のcaseへ処理を流すことは基本的にできません。

そのため、別のcaseの処理も実行したい場合は、goto caseを使って明示します。

8-5. goto文は現場の開発で使われる?

現場のC#開発でgoto文が使われることはありますが、頻度は高くありません。

多くの場面では、if文、ループ、break文、continue文、return文、例外処理、メソッド分割などで十分に対応できます。

ただし、多重ループから一気に抜けたい場合や、switch文でgoto caseを使って処理を共有したい場合など、限定的に使われることはあります。

現場で重要なのは、goto文を使うかどうかそのものではなく、コードが読みやすく保守しやすいかどうかです。

チームのコーディング規約で禁止されている場合は使わないようにしましょう。

また、レビューで「なぜgoto文を使ったのか」を説明できない場合は、別の書き方にした方が安全です。

まとめ

C#のgoto文は、指定したラベルやswitch文のcasedefaultへ処理をジャンプさせるための構文です。

基本的な書き方は次のとおりです。

C#
goto ラベル名;

ラベル名:
処理;

また、switch文では次のような書き方もできます。

C#
goto case ;
goto default;

goto文は便利に見えますが、処理の流れが追いにくくなり、スパゲッティコードやバグの原因になりやすいというデメリットがあります。

そのため、初心者のうちは多用しないことが大切です。

多くの場合、goto文は次の構文で書き換えられます。

C#
if
while
for
break
continue
return

さらに、複雑な処理はメソッド分割によって整理できます。

C#でgoto文を使ってもよいケースは、多重ループから一気に抜けたい場合や、switch文でgoto caseを使って処理を明示的に共有したい場合など、限られた場面です。

goto文を使う前には、次の点を確認しましょう。

「他の構文で書けないか」
「本当に読みやすくなるか」
「ラベル名はわかりやすいか」
「ジャンプ先が増えすぎていないか」
「チームのコーディング規約に違反していないか」

goto文は、使い方を間違えると危険ですが、仕組みを理解しておくことは大切です。

C#初心者は、まずif文、ループ、break文、continue文、return文をしっかり身につけたうえで、goto文は必要な場面だけ慎重に使うようにしましょう。