다음을 통해 공유


Jump 문 - break, continue, returngoto

jump 문은 무조건 제어를 전송합니다. 이 문은break 가장 가까운 바깥쪽 반복 문 또는 switch 문을 종료합니다. 이 문은continue 가장 가까운 바깥쪽 반복 문의 새 반복을 시작합니다. 문은 return 나타나는 함수의 실행을 종료하고 호출자에게 컨트롤을 반환합니다. 이 문은goto 레이블로 표시된 문으로 컨트롤을 전송합니다.

예외를 throw throw하고 무조건 제어를 전송하는 문에 대한 자세한 내용은 예외 처리 문 문서의 문 섹션을 참조 throw 하세요.

break 선언문

이 문은 break 가장 가까운 바깥쪽 반복 문 (즉, for, , foreach또는 while루프) 또는 doswitch 문을 종료합니다. 문은 break 종료된 문(있는 경우)을 따르는 문으로 제어를 전송합니다.

int[] numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
foreach (int number in numbers)
{
    if (number == 3)
    {
        break;
    }

    Console.Write($"{number} ");
}
Console.WriteLine();
Console.WriteLine("End of the example.");
// Output:
// 0 1 2 
// End of the example.

다음 예제와 break 같이 중첩된 루프에서 문은 이 루프를 포함하는 가장 안쪽 루프만 종료합니다.

for (int outer = 0; outer < 5; outer++)
{
    for (int inner = 0; inner < 5; inner++)
    {
        if (inner > outer)
        {
            break;
        }

        Console.Write($"{inner} ");
    }
    Console.WriteLine();
}
// Output:
// 0
// 0 1
// 0 1 2
// 0 1 2 3
// 0 1 2 3 4

루프 break 내에서 문을 사용하면 switch switch 섹션 끝에 있는 문이 문 밖으로만 컨트롤을 switch 전송합니다. 다음 예제와 switch 같이 문이 포함된 루프는 영향을 받지 않습니다.

double[] measurements = [-4, 5, 30, double.NaN];
foreach (double measurement in measurements)
{
    switch (measurement)
    {
        case < 0.0:
            Console.WriteLine($"Measured value is {measurement}; too low.");
            break;

        case > 15.0:
            Console.WriteLine($"Measured value is {measurement}; too high.");
            break;

        case double.NaN:
            Console.WriteLine("Failed measurement.");
            break;

        default:
            Console.WriteLine($"Measured value is {measurement}.");
            break;
    }
}
// Output:
// Measured value is -4; too low.
// Measured value is 5.
// Measured value is 30; too high.
// Failed measurement.

continue 선언문

이 문은 continue 다음 예제와 같이 가장 가까운 바깥쪽 반복 문(즉, for, , foreachwhile또는 do 루프)의 새 반복을 시작합니다.

for (int i = 0; i < 5; i++)
{
    Console.Write($"Iteration {i}: ");
    
    if (i < 3)
    {
        Console.WriteLine("skip");
        continue;
    }
    
    Console.WriteLine("done");
}
// Output:
// Iteration 0: skip
// Iteration 1: skip
// Iteration 2: skip
// Iteration 3: done
// Iteration 4: done

return 선언문

이 문은 return 나타나는 함수의 실행을 종료하고 컨트롤과 함수의 결과를 호출자에게 반환합니다.

함수 멤버가 값을 계산하지 않는 경우 다음 예제와 같이 식 없이 문을 사용합니다 return .

Console.WriteLine("First call:");
DisplayIfNecessary(6);

Console.WriteLine("Second call:");
DisplayIfNecessary(5);

void DisplayIfNecessary(int number)
{
    if (number % 2 == 0)
    {
        return;
    }

    Console.WriteLine(number);
}
// Output:
// First call:
// Second call:
// 5

앞의 예제에서 볼 수 있듯이 일반적으로 식 없이 문을 사용하여 return 함수 멤버를 일찍 종료합니다. 함수 멤버에 문이 포함되어 return 있지 않으면 마지막 문이 실행된 후 종료됩니다.

함수 멤버가 값을 계산하는 경우 다음 예제와 같이 식과 함께 문을 사용합니다 return .

double surfaceArea = CalculateCylinderSurfaceArea(1, 1);
Console.WriteLine($"{surfaceArea:F2}"); // output: 12.57

double CalculateCylinderSurfaceArea(double baseRadius, double height)
{
    double baseArea = Math.PI * baseRadius * baseRadius;
    double sideArea = 2 * Math.PI * baseRadius * height;
    return 2 * baseArea + sideArea;
}

문에 return 식이 있는 경우 비 기식이 아니면 해당 식을 함수 멤버의 반환 형식으로 암시적으로 변환할 수 있어야 합니다. 함수에서 반환되는 async 식은 함수의 반환 형식 중 어느 것이든 함수의 Task<TResult> 형식 인수로 ValueTask<TResult>암시적으로 변환할 수 있어야 합니다. 함수의 async 반환 형식이 Task 거나 ValueTask식 없이 문을 사용하는 return 경우

Ref가 반환됩니다.

기본적으로 이 문은 return 식의 값을 반환합니다. 변수에 대한 참조를 반환할 수 있습니다. 참조 반환 값(또는 ref 반환)은 메서드가 호출자에 대한 참조로 반환하는 값입니다. 즉, 호출자는 메서드에서 반환된 값을 수정할 수 있으며 해당 변경 내용은 호출된 메서드의 개체 상태에 반영됩니다. 이렇게 하려면 다음 예제와 같이 키워드와 함께 ref 문을 사용합니다return.

int[] xs = new int [] {10, 20, 30, 40 };
ref int found = ref FindFirst(xs, s => s == 30);
found = 0;
Console.WriteLine(string.Join(" ", xs));  // output: 10 20 0 40

ref int FindFirst(int[] numbers, Func<int, bool> predicate)
{
    for (int i = 0; i < numbers.Length; i++)
    {
        if (predicate(numbers[i]))
        {
            return ref numbers[i];
        }
    }
    throw new InvalidOperationException("No element satisfies the given condition.");
}

참조 반환 값을 사용하면 메서드가 값이 아닌 변수에 대한 참조를 호출자에게 다시 반환할 수 있습니다. 그런 다음 호출자는 반환된 변수를 값 또는 참조로 반환된 것처럼 처리하도록 선택할 수 있습니다. 호출자는 반환된 값( ref local)에 대한 참조인 새 변수를 만들 수 있습니다. 참조 반환 값은 메서드가 일부 변수에 대한 참조(또는 별칭)를 반환한다는 것을 의미합니다. 해당 변수의 범위에는 메서드가 포함되어야 합니다. 해당 변수의 수명은 메서드의 반환을 넘어 확장해야 합니다. 호출자가 메서드의 반환 값을 수정하면 메서드에서 반환되는 변수가 수정됩니다.

메서드가 참조 반환 값을 반환 한다고 선언하면 메서드가 변수에 별칭을 반환한다는 것을 나타냅니다. 디자인 의도는 코드 호출이 수정을 포함하여 별칭을 통해 해당 변수에 액세스하는 경우가 많습니다. 참조로 반환하는 메서드는 반환 형식 void을 가질 수 없습니다.

호출자가 개체의 상태를 수정하려면 참조 반환 값을 참조 변수로 명시적으로 정의된 변수에 저장해야 합니다.

ref 반환 값은 호출된 메서드 범위의 다른 변수에 대한 별칭입니다. 참조 반환의 모든 사용은 별칭이 있는 변수를 사용하는 것으로 해석할 수 있습니다.

  • 해당 값을 할당하면 별칭이 지정된 변수에 값을 할당합니다.
  • 해당 값을 읽을 때 별칭이 지정되는 변수의 값을 읽습니다.
  • 참조로 반환하는 경우 동일한 변수에 별칭을 반환합니다.
  • 참조로 다른 메서드 전달하는 경우 별칭이 지정된 변수에 대한 참조를 전달합니다.
  • ref 로컬 별칭을 만들 때 동일한 변수에 대한 새 별칭을 만듭니다.

ref 반환은 호출 메서드에 대한 ref-safe-context 여야 합니다. 즉, 다음을 의미합니다.

  • 반환 값은 메서드 실행 이상으로 확장되는 수명이 있어야 합니다. 즉, 반환하는 메서드에서 지역 변수가 될 수 없습니다. 클래스의 인스턴스 또는 정적 필드이거나 메서드에 전달된 인수일 수 있습니다. 지역 변수를 반환하려고 하면 컴파일러 오류 CS8168이 생성됩니다. "참조 로컬이 아니므로 참조로 로컬 'obj'를 반환할 수 없습니다."
  • 반환 값은 리터럴 null일 수 없습니다. ref 반환이 있는 메서드는 현재 값이 (uninstantiated) 값 또는 값 null 형식에 대한 nullable 값 형식 인 변수에 별칭을 반환할 수 있습니다.
  • 반환 값은 상수, 열거형 멤버, 속성의 값별 반환 값 또는 class 메서드 또는 struct메서드일 수 없습니다.

또한 비동기 메서드에서는 참조 반환 값이 허용되지 않습니다. 비동기 메서드는 실행을 완료하기 전에 반환할 수 있지만 반환 값은 아직 알 수 없습니다.

참조 반환 값을 반환하는 메서드는 다음을 수행해야 합니다.

  • 반환 형식 앞에 ref 키워드를 포함합니다.
  • 메서드 본문의 각 return 문에는 반환된 인스턴스의 이름 앞에 ref 키워드가 포함됩니다.

다음 예제에서는 이러한 조건을 충족하고 이름이 지정된 p개체에 대한 참조를 반환하는 메서드를 Person 보여 줍니다.

public ref Person GetContactInformation(string fname, string lname)
{
    // ...method implementation...
    return ref p;
}

다음은 메서드 시그니처와 메서드 본문을 모두 보여 주는 보다 완전한 참조 반환 예제입니다.

public static ref int Find(int[,] matrix, Func<int, bool> predicate)
{
    for (int i = 0; i < matrix.GetLength(0); i++)
        for (int j = 0; j < matrix.GetLength(1); j++)
            if (predicate(matrix[i, j]))
                return ref matrix[i, j];
    throw new InvalidOperationException("Not found");
}

호출된 메서드는 반환 값을 참조로 ref readonly 반환하도록 선언하고 호출 코드에서 반환된 값을 수정할 수 없도록 강제할 수도 있습니다. 호출 메서드는 로컬 ref readonly 참조 변수에 값을 저장하여 반환된 값을 복사하지 않도록 할 수 있습니다.

다음 예제에서는 두 String 개의 필드 Title 가 있는 클래스를 정의 Book 합니다Author. 또한 개체의 BookCollectionBook 프라이빗 배열을 포함하는 클래스를 정의합니다. 개별 책 개체는 해당 GetBookByTitle 메서드를 호출하여 참조로 반환됩니다.


public class Book
{
    public string Author;
    public string Title;
}

public class BookCollection
{
    private Book[] books = { new Book { Title = "Call of the Wild, The", Author = "Jack London" },
                        new Book { Title = "Tale of Two Cities, A", Author = "Charles Dickens" }
                       };
    private Book nobook = null;

    public ref Book GetBookByTitle(string title)
    {
        for (int ctr = 0; ctr < books.Length; ctr++)
        {
            if (title == books[ctr].Title)
                return ref books[ctr];
        }
        return ref nobook;
    }

    public void ListBooks()
    {
        foreach (var book in books)
        {
            Console.WriteLine($"{book.Title}, by {book.Author}");
        }
        Console.WriteLine();
    }
}

호출자가 메서드에서 반환한 GetBookByTitle 값을 참조 로컬로 저장하면 다음 예제와 같이 호출자가 반환 값에 적용하는 변경 내용이 개체에 BookCollection 반영됩니다.

var bc = new BookCollection();
bc.ListBooks();

ref var book = ref bc.GetBookByTitle("Call of the Wild, The");
if (book != null)
    book = new Book { Title = "Republic, The", Author = "Plato" };
bc.ListBooks();
// The example displays the following output:
//       Call of the Wild, The, by Jack London
//       Tale of Two Cities, A, by Charles Dickens
//
//       Republic, The, by Plato
//       Tale of Two Cities, A, by Charles Dickens

goto 선언문

이 문은 goto 다음 예제와 같이 레이블로 표시된 문으로 컨트롤을 전송합니다.

var matrices = new Dictionary<string, int[][]>
{
    ["A"] =
    [
        [1, 2, 3, 4],
        [4, 3, 2, 1]
    ],
    ["B"] =
    [
        [5, 6, 7, 8],
        [8, 7, 6, 5]
    ],
};

CheckMatrices(matrices, 4);

void CheckMatrices(Dictionary<string, int[][]> matrixLookup, int target)
{
    foreach (var (key, matrix) in matrixLookup)
    {
        for (int row = 0; row < matrix.Length; row++)
        {
            for (int col = 0; col < matrix[row].Length; col++)
            {
                if (matrix[row][col] == target)
                {
                    goto Found;
                }
            }
        }
        Console.WriteLine($"Not found {target} in matrix {key}.");
        continue;

    Found:
        Console.WriteLine($"Found {target} in matrix {key}.");
    }
}
// Output:
// Found 4 in matrix A.
// Not found 4 in matrix B.

앞의 예제와 같이 문을 사용하여 goto 중첩된 루프에서 벗어날 수 있습니다.

팁 (조언)

중첩 루프를 사용하는 경우 별도의 루프를 별도의 메서드로 리팩터링하는 것이 좋습니다. 이로 인해 문이 없는 더 간단하고 읽기 쉬운 코드가 goto 발생할 수 있습니다.

다음 예제와 switch 같이 문의 문을 사용하여 goto 일정한 대/소문자 레이블이 있는 switch 섹션으로 제어를 전송할 수도 있습니다.

using System;

public enum CoffeeChoice
{
    Plain,
    WithMilk,
    WithIceCream,
}

public class GotoInSwitchExample
{
    public static void Main()
    {
        Console.WriteLine(CalculatePrice(CoffeeChoice.Plain));  // output: 10.0
        Console.WriteLine(CalculatePrice(CoffeeChoice.WithMilk));  // output: 15.0
        Console.WriteLine(CalculatePrice(CoffeeChoice.WithIceCream));  // output: 17.0
    }

    private static decimal CalculatePrice(CoffeeChoice choice)
    {
        decimal price = 0;
        switch (choice)
        {
            case CoffeeChoice.Plain:
                price += 10.0m;
                break;

            case CoffeeChoice.WithMilk:
                price += 5.0m;
                goto case CoffeeChoice.Plain;

            case CoffeeChoice.WithIceCream:
                price += 7.0m;
                goto case CoffeeChoice.Plain;
        }
        return price;
    }
}

문 내에서 switch 문을 goto default; 사용하여 레이블이 있는 switch 섹션 default 으로 제어를 전송할 수도 있습니다.

지정된 이름의 레이블이 현재 함수 멤버에 없거나 문이 레이블 범위 내에 없는 경우 goto 컴파일 시간 오류가 발생합니다. 즉, 문을 사용하여 goto 현재 함수 멤버에서 또는 중첩된 범위로 제어를 전송할 수 없습니다.

C# 언어 사양

자세한 내용은 C# 언어 사양의 다음 섹션을 참조하세요.

참고하십시오