C #에서 "variable! = null"대신 "null! = variable"이 자주 표시되는 이유는 무엇입니까?


103

C #에서 조건을 설명하는 순서에 대한 실행 속도에 차이가 있습니까?

if (null != variable) ...
if (variable != null) ...

최근부터 첫 번째를 자주 보았고 두 번째에 익숙해 져서 눈에 띄었습니다.

차이가 없다면 첫 번째의 장점은 무엇입니까?



일부 프로그래밍 언어는 if 조건에서 값 초기화를 지원합니다. 이러한 언어에서 LValue를 RValue와 비교하려면 if (1 == i)와 같이 왼쪽에 리터럴을 사용하는 것이 좋습니다. 그래서 우연히 = 대신 ==를 넣으면 컴파일러 오류가 발생합니다.
Jugal Panchal

답변:


160

C의 보류입니다. C에서 잘못된 컴파일러를 사용하거나 경고가 충분히 높지 않으면 경고없이 컴파일됩니다 (실제로 합법적 인 코드 임).

// Probably wrong
if (x = 5)

당신이 실제로 의미했을 때

if (x == 5)

C에서 다음을 수행하여이 문제를 해결할 수 있습니다.

if (5 == x)

여기에 오타가 있으면 잘못된 코드가 생성됩니다.

이제 C #에서 이것은 모두 파이 플입니다. 두 개의 부울 값 (드물게 IME)을 비교하지 않는 한 "if"문은 시작하는 부울 표현식이 필요하고 " x=5" 유형 은 Int32, 아니기 때문에 더 읽기 쉬운 코드를 작성할 수 있습니다 Boolean.

동료의 코드에서 이것을 본다면 현대 언어로 교육하고 미래에 더 자연스러운 형식을 작성하도록 제안하십시오.


6
내 동료들은 모두 나를 미치게 만들고 if ... (나중에 '알지 못하고'무언가를 추가하는 경우에 대비하여 if ... 뒤에 하나의 문장에 대해서도 중괄호를 원한다.) F # 및 Boo (및 YAML)에 굴러서 들여 쓰기없이 언어를 읽을 수없는 경우 언어의 일부로 만드십시오.
Benjol

48
중괄호를 추가하는 것은 합리적입니다. IMO-C #은 확실히 문제가되는 것을 막으려는 시도를하지 않습니다. 이것은 "상수 == 변수"문제와는 매우 다릅니다.
Jon Skeet

6
a if (this! = that) {performAsSuch (); } 실제로 꽤 건강합니다. "나중에 추가"에 대한 주장은 (a = 5) 오타를 피하거나 발견하지 않는 것만 큼 깨지기 쉽습니다.
jpinto3912

3
@jpinto : 여기서 무슨 말을 하려는지 잘 모르겠습니다. 단일 문장을 중괄호로 묶는 것을 좋아하는지, 그렇지 않은지? 이 질문과 변수 비즈니스의 차이점은 C #에서 오타가있는 코드가 잘못된 코드이므로 컴파일러가 중지한다는 것입니다. 동일 하지 않습니다 에 괄호를 넣어하지 마찬가지.
존 소총

3
@Benjol else { }누군가가 나중에 뭔가를 추가해야하고 else키워드 자체 를 작성하는 것을 잊었을 경우를 대비 하여 항상 빈 절을 제공하는 것을 잊지 마십시오 . (농담)
Jeppe Stig Nielsen

12

먼저 null을 사용하는 좋은 이유가 있습니다. if(null == myDuck)

귀하의 경우 class Duck오버라이드 (override) ==연산자, 후 if(myDuck == null)무한 루프에 갈 수 있습니다.

사용하여 null실제로 처음 사용에게 기본 같음 비교를하고 당신이 의도했는지 않습니다.

(결국 그런 식으로 작성된 코드를 읽는 데 익숙해 졌다고 들었습니다. 아직 그 변환을 경험하지 못했습니다).

다음은 예입니다.

public class myDuck
{
    public int quacks;
    static override bool operator ==(myDuck a, myDuck b)
    {
        // these will overflow the stack - because the a==null reenters this function from the top again
        if (a == null && b == null)
            return true;
        if (a == null || b == null)
            return false;

        // these wont loop
        if (null == a && null == b)
            return true;
        if (null == a || null == b)
            return false;
        return a.quacks == b.quacks; // this goes to the integer comparison
    }
}

11
이것은 잘못되었습니다. 비추천. ==연산자 위에 마우스를 올려 놓기 만하면 두 경우 모두 사용자 정의 오버로드가 사용되는 것을 볼 수 있습니다. 물론 a이전에 확인한 b다음 a오른쪽 피연산자에서 왼쪽 피연산자로 위치를 바꾸면 미묘한 차이를 만들 수 있습니다 . 그러나 b이전 a에 확인한 다음 b == null순서를 반대로 할 수도 있습니다. 운영자가 자신을 호출하는 것은 모두 혼란 스럽습니다. 대신 object원하는 오버로드를 얻으려면 피연산자 (또는 둘 다)를 캐스트 하십시오. 좋아요 if ((object)a == null)또는 if (a == (object)null).
Jeppe Stig Nielsen

10

모두가 이미 언급했듯이 실수로 두 번째 등호 기호를 잊어 버린 경우 잘못된 코드를 얻을 수있는 C 언어에서 다소간 발생합니다. 그러나 C #과 일치하는 또 다른 이유는 가독성입니다.

이 간단한 예를 들어 보겠습니다.

if(someVariableThatShouldBeChecked != null
   && anotherOne != null
   && justAnotherCheckThatIsNeededForTestingNullity != null
   && allTheseChecksAreReallyBoring != null
   && thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded != null)
{
    // ToDo: Everything is checked, do something...
}

모든 null 단어를 처음으로 바꾸면 모든 검사를 훨씬 쉽게 찾을 수 있습니다.

if(null != someVariableThatShouldBeChecked
   && null != anotherOne
   && null != justAnotherCheckThatIsNeededForTestingNullity
   && null != allTheseChecksAreReallyBoring
   && null != thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded)
{
    // ToDo: Everything is checked, do something...
}

따라서이 예제는 잘못된 예제 일 수 있지만 (코딩 지침 참조) 전체 코드 파일을 빠르게 스크롤하는 것에 대해 생각해보십시오. 단순히 패턴을보고

if(null ...

다음에 무엇이 올지 즉시 알 수 있습니다.

그 반대 의 경우에는 널성 검사를 확인하기 위해 항상 줄 끝까지 스캔 해야합니다. 그저 거기에서 어떤 종류의 검사가 수행되는지 알아 내기 위해 잠시 비틀 거리게합니다. 따라서 구문 강조가 도움이 될 수 있지만 해당 키워드가 앞줄이 아닌 줄 끝에 있으면 항상 속도가 느려집니다.


9

나는 이것이 언어를 바꾼 C 프로그래머라고 생각합니다.

C에서는 다음과 같이 작성할 수 있습니다.

int i = 0;
if (i = 1)
{
    ...
}

여기에서 단일 등호를 사용하면 코드가 1을 변수 i에 할당 한 다음 1을 반환하고 (할당은 표현식) if 문에서 1을 사용하여 true로 처리됩니다. 즉, 위는 버그입니다.

그러나 C #에서는 이것이 불가능합니다. 실제로 둘 사이에는 차이가 없습니다.


1
"그러나 C #에서는 이것이 불가능합니다."컴파일러가 불평하지 않고서는 if 문에 부울식이 필요하고 제공된 것은 int 형식이기 때문입니다.
Robert Harvey

4

이전에는 사람들이 '!'를 잊어 버렸습니다. (또는 평등에 대한 추가 '=', 찾기가 더 어렵습니다) 비교 대신 할당을 수행하십시오. null을 앞에두면 null은 l- 값이 아니므로 (IE를 할당 할 수 없음) 버그 가능성을 제거합니다.

대부분의 최신 컴파일러는 요즘 조건부 할당을 수행 할 때 경고를 표시하고 C #은 실제로 오류를 제공합니다. 대부분의 사람들은 일부 사람들이 읽기 쉽기 때문에 var == null 스키마를 고수합니다.


모든 C # 컴파일러 (이것은 C # 질문입니다)는 표현식이 부울이 아닌 "if"문을 컴파일하지 못합니다 ...
Jon Skeet

4

이 규칙을 따를 때 어떤 이점도 보이지 않습니다. 부울 유형이 존재하지 않는 C에서는 다음과 같이 작성하는 것이 유용합니다.

if( 5 == variable)

보다는

if (variable == 5)

등호 중 하나를 잊어 버리면 결국

if (variable = 5)

변수에 5를 할당하고 항상 참으로 평가합니다. 그러나 Java에서 부울은 부울입니다. 그리고! =를 사용하면 이유가 전혀 없습니다.

하지만 한 가지 좋은 조언은

if (CONSTANT.equals(myString))

보다는

if (myString.equals(CONSTANT))

NullPointerExceptions를 피하는 데 도움이되기 때문입니다.

내 조언은 규칙의 정당성을 요청하는 것입니다. 없는 경우 왜 따라야합니까? 가독성에 도움이되지 않습니다


0

나에게는 항상 당신이 선호하는 스타일이었습니다.

@Shy-그런 다음 연산자를 혼동하면 컴파일 오류가 발생하거나 버그가있는 코드를 실행해야합니다. 예기치 않은 동작을 생성했기 때문에 나중에 돌아와서 당신을 물어 뜯는 버그입니다.


나는 이제까지 "일정 == 변수"양식을 선호하는 사람이 들었어요 생각하지 않는 다른 이미 C #으로 처리되어 안전을 이유로,보다 있습니다.
Jon Skeet

나는 "variable == constant"나 자신을 선호하지만, 프로그래머가 그들이 더 자연스럽게 읽는다고 느끼기 때문에 반전을 채택하는 것을 보았습니다.
TheCodeJunkie

1
수년간의 C 세뇌를 가진 사람들은 모두 그들 뒤에 있었습니까, 아니면 진정한 선택 이었습니까?
Jon Skeet

0

많은 사람들이 지적했듯이 컴파일러가 합법적 인 것으로 허용했기 때문에 컴파일 오류를 식별하는 데 사용되었던 대부분의 오래된 C 코드입니다.

Java, go와 같은 새로운 프로그래밍 언어는 이러한 컴파일 오류를 캡처 할만큼 똑똑합니다.

코드에서 조건과 같은 "null! = 변수"를 사용하면 안됩니다.


-4

한 가지 더 ... 변수를 상수 (예 : 정수 또는 문자열)와 비교하는 경우 NullPointerExceptions가 발생하지 않으므로 상수를 왼쪽에 두는 것이 좋습니다.

int i;
if(i==1){        // Exception raised: i is not initialized. (C/C++)
  doThis();
}

이므로

int i;
if(1==i){        // OK, but the condition is not met.
  doThis();
}

이제 기본적으로 C #은 모든 변수를 인스턴스화하므로 해당 언어에서 문제가 발생하지 않아야합니다.


1
코드의 첫 번째 비트에 어떤 컴파일러를 사용하고 있는지 확실하지 않지만 컴파일해야합니다 (일반적으로 경고와 함께). i의 값은 정의되지 않았지만 SOME 값이 있습니다.
Dolphin

물론 두 코드 모두 컴파일됩니다! 그게 바로 문제입니다. 첫 번째 코드를 실행 해보십시오 그리고 당신은 내가 무슨 뜻인지 이해하게 될 것 "예외가 제기 ..."
karlipoppins

또한 둘 사이의 차이를 얻지 못합니다. 자세히 설명 할 수 있습니까?
mfazekas

C / C ++에서 int * i를 선언하지 않는 한 예외는 없습니다.이 경우에도 포인터를 비교하고 예외를 던지지 않습니다. Dolphin이 값이 정의되지 않았지만 예외를 생성하지 않는다고 언급 한 것처럼.
Cobusve

예외 i는 없습니다. 적절한 초기화가없는 임의의 값 이라고 가정 해 보겠습니다 . 표현식은 c / c ++에서 완전히 동일한 의미를 갖습니다
Raffaello
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.