[c#] 이 두 줄이 같은가요? … : ‘vs’?? ‘?

이 두 줄에 차이가 있습니까?

MyName = (s.MyName == null) ? string.Empty : s.MyName

또는

MyName = s.MyName ?? string.Empty



답변

업데이트 : 나는이 주제를 더 깊이 논의하는 블로그 포스트를 썼습니다. http://www.codeducky.org/properties-fields-and-methods-oh-my/


일반적으로 동일한 결과를 반환합니다. 그러나 첫 번째 예제 MyName에서는 MyNamegetter가 두 번 실행되고 두 번째 예제에서는 한 번만 실행 되기 때문에 속성 일 때 눈에 띄는 차이가 발생하는 몇 가지 경우 가 있습니다.

예를 들어, MyName두 번 실행하면 성능 차이가 발생할 수 있습니다 .

string MyName
{
    get
    {
        Thread.Sleep(10000);
        return "HELLO";
    }
}

또는 상태 저장 인 MyName경우 두 번 실행하면 다른 결과를 얻을 수 있습니다 MyName.

private bool _MyNameHasBeenRead = false;

string MyName
{
    get
    {
        if(_MyNameHasBeenRead)
                throw new Exception("Can't read MyName twice");
        _MyNameHasBeenRead = true;
        Thread.Sleep(10000);
        return "HELLO";
    }
}

또는 다른 스레드에서 변경 MyNameMyName수있는 경우 두 번 실행하면 다른 결과를 얻을 수 있습니다.

void ChangeMyNameAsync()
{
    //MyName set to null in another thread which makes it 
    //possible for the first example to return null
    Task.Run(() => this.MyName = null);
}

string MyName { get; set; }

실제 코드가 컴파일되는 방법은 다음과 같습니다. 먼저 삼항식이있는 조각 :

IL_0007:  ldloc.0     // s
IL_0008:  callvirt    s.get_MyName       <-- first call
IL_000D:  brfalse.s   IL_0017
IL_000F:  ldloc.0     // s
IL_0010:  callvirt    s.get_MyName       <-- second call
IL_0015:  br.s        IL_001C
IL_0017:  ldsfld      System.String.Empty
IL_001C:  call        set_MyName

다음은 null-coalescing 연산자가있는 부분입니다.

IL_0007:  ldloc.0     // s
IL_0008:  callvirt    s.get_MyName       <-- only call
IL_000D:  dup
IL_000E:  brtrue.s    IL_0016
IL_0010:  pop
IL_0011:  ldsfld      System.String.Empty
IL_0016:  call        s.set_MyName

보시다시피 삼항 연산자에 대한 컴파일 된 코드는 속성 값을 얻기 위해 두 번의 호출을 수행하는 반면 null 통합 연산자는 1 만 수행합니다.


답변

속성이 단순한 getter 이상인 경우 첫 번째 항목에 대해 null이 아닌 경우 함수를 두 번 실행할 수 있습니다.

속성이 상태 저장 객체에있는 경우 속성에 대한 두 번째 호출은 다른 결과를 반환 할 수 있습니다.

class MyClass
{
    private IEnumerator<string> _next = Next();

    public MyClass()
    {
        this._next.MoveNext();
    }

    public string MyName
    {
        get
        {
            var n = this._next.Current;
            this._next.MoveNext();
            return n;
        }
    }


    public static IEnumerator<string> Next()
    {
        yield return "foo";
        yield return "bar";
    }
}

또한 문자열이 아닌 경우 클래스는 삼항 연산자와 다른 작업을 수행하기 위해 ==를 오버로드 할 수 있습니다. 삼항 연산자가 오버로드 될 수 있다고 생각하지 않습니다.


답변

유일한 차이점은 s.MyName두 번 또는 한 번 평가하는지 여부 입니다. 첫 번째는 s.MyNamenull이 아닌 경우 두 번 수행하고 두 번째는 한 번만 평가합니다.

대부분의 경우이 차이는 중요하지 않으며, 더 명확하고 간결하기 때문에 두 번째를 사용하겠습니다.


답변

예, 둘 다 동일하며 null 통합 연산자 입니다.

피연산자가 null이 아니면 왼쪽 피연산자를 반환합니다. 그렇지 않으면 오른손 피연산자를 반환합니다.

효율성에 대해 이야기하면

string MyName = (s.MyName == null) ? string.Empty : s.MyName;
string MyName2 = s.MyName ?? string.Empty;

dissembler를 사용 하면 첫 번째 명령문 은 컴파일러에서 19 개의 명령문 을 실행 해야하는 반면 두 번째 명령문은 12 개의 명령문 만 실행하면된다는 것을 알 수 있습니다.


답변

예, 그들은 똑같이합니다. ??null 확인을위한 속기입니다.


답변

그들은 동일한 작업을 수행합니다.

유일한 차이점은 동료 또는 코드를 읽는 사람이 구문을 이해하는지 여부에 대한 가독성입니다.

편집 : 또한 첫 번째 옵션은 속성을 MyName두 번 평가할 수 있습니다 .


답변

아뇨. 둘 다 같은 일을하고 있습니다. 두 번째는 효율적입니다. null이 아닌 경우 실제 값을 반환합니다. 그렇지 않으면 오른쪽 값이 반환됩니다.

http://msdn.microsoft.com/en-us/library/ms173224.aspx를 참조하십시오 .

도움이 되었기를 바랍니다.