누구든지 여전히 C #에서 [goto]를 사용합니까? 그렇다면 그 이유는 무엇입니까? [닫은]


104

누군가가 여전히 C #에서 "goto"키워드 구문을 사용하는지 여부와 그 이유가 무엇인지 궁금합니다.

나는 독자가 코드를 훑어 보도록 만드는 어떤 진술을 나쁜 습관으로 보는 경향이 있지만 그러한 구문을 사용하는 데 신뢰할 수있는 시나리오가 있는지 궁금합니다.

Goto 키워드 정의


3
"아직"이란 무슨 뜻입니까? 사람들이 [C #에서] 항상 사용했던 기간이 있었나요?
Massif

4
@Massif : "still"은 스파게티 코드의 전주곡으로 "goto"를 사용하는 현대적인 견해와 소스 코드의 가독성 부족을 강조하기위한 것입니다. 이 특정 키워드를 포함하여 코드 예제를 보는 경우는 매우 드뭅니다. 이것이 제가 처음에 질문하고 싶었던 이유였습니다.
Brian Scott

50
독자가 코드를 "점프하는"것이 나쁜 습관이라면 "break", "continue", "throw"및 "return"도 피합니까? 그것들은 모두 제어 흐름에서 분기를 발생시키고 때로는 비 로컬 분기를 발생시킵니다. "Throw"는 goto와 달리 어디로 가는지 알려주지 않습니다.
Eric Lippert

2
나는 goto루프를 끊고 특정 조건에 따라 시작 문으로 돌아가는 데 사용합니다
Nitin Sawant

3
나는 고토를 좋아합니다. 코드를 읽기 어렵 기 때문에 피하라고하는 사람들의 경향 때문에 피하려고했습니다. 어셈블리 언어와 분기 문을 배웠으므로 때때로 코드를 더 읽기 쉽게 만들 수 있다고 생각합니다. 나는 한 가지 방법으로 여러 번 사용하고 코드에서 너무 아래로 점프하면 이익보다 해를 끼칠 수 있다고 생각합니다. 그러나 고토가 여기에서 잘 작동 할 것이라고 생각한다면, 단순한 고토가 가끔씩 당신의 길을 벗어나지 말아야합니다. 단지 일반적인 합의가 그것을 피하는 것이기 때문입니다.
eaglei22

답변:


93

goto가 실제로 가독성을 향상시킬 수있는 (드문) 경우가 있습니다. 실제로 링크 한 문서에는 두 가지 예가 나열되어 있습니다.

goto의 일반적인 용도는 제어를 특정 switch-case 레이블 또는 switch 문의 기본 레이블로 전송하는 것입니다.

goto 문은 깊이 중첩 된 루프를 벗어나는데도 유용합니다.

다음은 후자의 예입니다.

for (...) {
    for (...) {
        ...
        if (something)
            goto end_of_loop;
    }
}

end_of_loop:

물론 코드를 함수로 리팩토링하거나 주변에 더미 블록을 사용하는 등이 문제를 해결하는 다른 방법도 있습니다 (자세한 내용은 이 질문 참조). 참고로 Java 언어 디자이너는 goto를 완전히 금지 하고 대신 레이블이 지정된 break 문을 도입 하기로 결정했습니다 .


47
일반적으로 나는 것 시도 난 그냥에서 반환 할 수있는 별도의 방법 ...에 루프를 넣어이 리팩토링
존 소총

2
@Heinzi-나는 고토가 보증되는 것을 보지 못했습니다. Jon이 말했듯이 그것이 "보증"이라면 코드는 리팩토링을 구걸하고 있습니다.
manojlds

29
라벨 휴식,이 같은 나치의 일을하기 때문에 고토 말을 단지 더 이상 방법 ....
예수 라모스

20
@Jesus하지만 goto를 사용하면 어디든 갈 수 있습니다. 레이블이있는 브레이크는 루프 밖으로 나가는 것을 보장합니다.
mihsathe

1
모험심이없고 주소와 함께 goto를 사용하지 않는 한 (이전에 수행 한 적이 있음) 그 문제는 완화됩니다. 그리고 누군가가 goto 문을 악용하기 위해 C # 및 Java 코드에서 우회 후크를 사용하고 있는지 의심합니다.
Jesus Ramos

65

이 부분이 기억 나

switch (a)     
{ 
    case 3: 
        b = 7;
        // We want to drop through into case 4, but C# doesn't let us
    case 4: 
        c = 3;
        break; 
    default: 
        b = 2;
        c = 4;
        break; 
}

이와 같은 것에

switch (a)     
{
    case 3: 
        b = 7;
        goto case 4;    
    case 4: 
        c = 3;
        break;     
    default: 
        b = 2;
        c = 4;
        break;
}

이것을 참조하십시오


17
나는 실제로 이것이 [goto]를 사용하는 가장 타당한 이유라고 생각합니다. 적어도이 시나리오에서는 break 문없이 케이스가 서로 떨어지는 것을 인식하지 못하는 프로그래머가 가독성을 높입니다.
Brian Scott

11
@Brian Scott, V4Vendetta. 내가 착각하지 않는 한 첫 번째 문장은 C #으로 컴파일되지 않습니다. 그것은 프로그래머의 이해를 도울 것입니다.
Jodrell

2
V4Vendetta 첫 번째 코드 스 니펫에 중단을 삽입 한 이유는 무엇입니까? 중단없이 표시하는 것이 더 낫습니다. 그렇지 않으면 두 조각이 다른 작업을 수행합니다. 두 번째 예제에서 goto가 필요한 이유는 첫 번째 예제가 C #에서 컴파일되지 않기 때문입니다 (C 에서처럼).
Stephen Holt

23

C # 5에서 비동기 메서드를 사용할 때 컴파일러가 생성하는 코드의 종류를 보여주기 위해 Eduasync 에서 광범위하게 사용합니다 . 반복자 블록에서도 동일한 것을 볼 수 있습니다.

"일반"코드에서는 마지막으로 사용한 시간이 기억 나지 않습니다.


1
이 접근 방식이 선호되는 이유 또는 단순히 개인적인 선호 사항에 대한 작은 예를 제공 할 수 있습니까?
Brian Scott

1
@Brian : 당신이 의미하는 바가 명확하지 않습니다. Eduasync 컴파일러가 당신을 위해 무엇에 해당하는 C # 코드를 보여줍니다 - 그리고 ... 사용을 효과적으로, 고토 코드를 생성
존 소총

9

goto는 break가 잘 작동하지 않는 많은 루프 (예 : 오류 조건)에서 벗어나는 데 적합하며 Kragen이 말했듯이 goto는 컴파일러에서 switch 문 및 기타 사항을 생성하는 데 사용됩니다.


7
확실히 "break"/ "continue"는 다음 단계가 발생하는 위치를 이해하기 위해 소스 코드를 건너 뛰도록 코드 편집기를 요구하는 것보다 루프 관리에 대한 더 나은 접근 방식입니까?
Brian Scott

6
중첩 루프가있는 경우에는 그렇지 않습니다.
Jesus Ramos

1
좋아, 나는 이것을 유효한 시나리오로 볼 수있다.
Brian Scott

1
오류 상태에서 예외 발생을 고려해야합니다.
Jodrell

6
예외없이 내부적으로 오류를 처리하려면 이것이 유효한 방법입니다.
Jesus Ramos

8

를 사용한 기억이 없습니다 goto. 그러나 어쩌면 그것은 당신이 정말로 (NO 종료하려면 결코 영원히 루프의 의도를 향상 break,하지만 여전히 수 return또는 throw) :

forever: {
  // ...
  goto forever;
}

다시 말하지만 간단한 while (true)것으로 충분합니다 ...

또한 루프의 중간에서 루프의 첫 번째 반복을 시작하려는 상황에서 사용할 있습니다 . 여기 에서 예제를보십시오.


링크 대답은 의 "흥미로운"사용을 포함하고 goto..하고 while(true) {..}.. 재미있는 사용하지 않습니다
user2864740

5

컴파일러는 goto생성 된 반복기 블록 유형 ( yield return키워드를 사용할 때 생성됨)과 같이 생성 된 다양한 코드 조각에서 명령문을 사용합니다 . 생성 된 XML 직렬화 유형도 goto어딘가에 몇 개의 명령문을 가지고 있다고 확신합니다 .

C # 컴파일러가이를 처리하는 이유 / 방법에 대한 자세한 내용 은 반복자 블록 구현 세부 정보 : 자동 생성 상태 머신 을 참조하세요.

생성 된 코드 외에는 goto일반 코드에서 명령문 을 사용할 이유가 없습니다. 코드를 이해하기 어렵게 만들고 결과적으로 오류가 발생하기 쉽습니다. 반면에goto 같이 생성 된 코드에서 명령문을 하면 생성 프로세스를 단순화 할 수 있으며 생성 된 코드를 아무도 읽거나 수정할 수없고 기계가 쓰기를 수행하기 때문에 실수 할 가능성이 없기 때문에 일반적으로 괜찮습니다.

고전적인 프로그래밍 역사의 일부뿐만 아니라 반대 주장에 유해한 것으로 간주되는 Go-to 문을 참조하십시오 goto.


4
이것은 어리석은 일입니다. 다른 답변에서 설명한 것처럼 goto가 유용한 몇 가지 경우가 있습니다. 당신이 그것들을 명시 적으로 문지르거나 "그것이 틀렸다"고 말하는 것은, 음, 잘못되었습니다.
o0 '.

@Lohoris 나는 그것을 사지 않을 것입니다-goto가 "가독성을 향상시키는"(여기에 답변을 포함하여) 어디에서 본 모든 예는 간단한 리팩토링 후에 훨씬 더 읽기 쉬울 것입니다.
Justin

3
@Justin 아니요, 때때로 중첩 된 루프는 예를 들어 배열 배열을 순회하는 경우에 가장 자연스러운 방법입니다.
o0 '.

6
@Justin 함수에 포함시키는 것이 항상 더 명확한 것은 아닙니다. 종교적으로 싫어하는 것을 피하기 위해 (고토를 사용하여) 무언가를 강요하고 있습니다. 뭔가 잘못하고 있다는 명확한 표시.
o0 '.

3
@Justin 함수 호출에는 오버 헤드가 있습니다. goto하지 않습니다. 고려해야 할 것.
Dan Bechard

2

프로세서는 적어도 하나의 점프 명령을 구현하고 많은 명령문이 구현 또는 해석에 사용한다고 확신합니다.

3 세대 또는 4 세대 언어를 사용할 때 좋은 점 중 하나는 이러한 물리적 세부 사항이 우리에게서 추상화된다는 것입니다. 우리는 유출 추상화법칙을 염두에 두어야 하지만 의도 한대로 도구를 사용해야한다고 생각합니다 ( 죄송합니다 ). 내가 코드를 작성하고 있고 goto좋은 생각처럼 보인다면 리팩토링해야 할 때입니다. 구조화 된 언어의 목적은 이러한 "점프"를 피하고 엔지니어링에서 논리적 흐름을 만드는 것입니다.

나는 사용을 피해야 break하지만 성능상의 이점을 간과 할 수 없습니다. 그러나 상호 적으로 필요한 중첩 루프가있는 경우 break리팩토링 해야합니다 .

누군가 goto리팩토링보다 더 나은 사용을 제안 할 수 있다면 기꺼이 내 대답을 철회 할 것입니다.

나는 내가 여기 " 자전거 창고 " 로 서두르지 않기를 바랍니다 . Kragen이 말했듯이 Dijkstra 에게 충분한 것은 나에게 충분합니다.


1
복용하는 dynamic객체를 내가 필요로하는 값으로 내려 여러 사전을 포함하고 그것의 객체 그래프를 산책. 매개 변수가 dynamic있지만 정확한 개체 모양을 기대하는 메서드를 사용하는 것은 의미가 없습니다 . goto를 사용하여 여러 레이어를 분리하고 이러한 개체 컬렉션을 계속 진행합니다. [더 나은 액세스를 제공 할 수 있도록 나는 반사 또는 동적 그래서 그것이, 종류를 보유하고 있지 않습니다]
크리스 Marisic

-6

Goto는 결코 더 좋지 않습니다. 그리고 계속, 브레이크 (스위치 / 케이스 제외), (다중) 리턴, 던지기도 최소한으로 유지해야합니다. 네스트 루프의 중간에서 벗어나고 싶지 않습니다. 항상 루프 제어 명령문에 모든 루프 제어가 있어야합니다. 들여 쓰기에는 정보가 있으며 이러한 모든 명령문은 해당 정보를 버립니다. 모든 들여 쓰기를 제거하는 것이 좋습니다.


10
루프 실행을 유지하는 데 아무런 의미가 없으면 루프에서 벗어나고 싶을 것입니다. 그렇지 않으면 이유없이 더 긴 루프에서 더 많은 처리 시간을 낭비하게됩니다.
Skuld

12
@Kirk, 이것은 양적인 것보다 의견처럼 들리나요?
Brian Scott
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.