Are these two lines the same, '? … :' vs &

2020-05-14 04:45发布

Is there a difference between these two lines?

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

or

MyName = s.MyName ?? string.Empty

标签: c#
7条回答
孤傲高冷的网名
2楼-- · 2020-05-14 05:00

UPDATE: I wrote a blog post that discusses this topic in more depth. http://www.codeducky.org/properties-fields-and-methods-oh-my/


Generally they will return the same result. However, there are a few cases where you will experience noticeable differences when MyName is a property because the MyName getter will be executed twice in the first example and only once in the second example.

For example, you may experience performance differences from executing MyName twice:

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

Or you may get different results from executing MyName twice if MyName is stateful:

private bool _MyNameHasBeenRead = false;

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

Or you may get different results from executing MyName twice if MyName can be changed on a different thread:

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; }  

Here's how the actual code is compiled. First the piece with the ternary expression:

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

and here is the piece with the null-coalescing operator:

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

As you can see the compiled code for the ternary operator will make two calls to get the property value, whereas the null-coalescing operator will only do 1.

查看更多
够拽才男人
3楼-- · 2020-05-14 05:03

Yes, both are the same, and it is the null-coalescing operator.

It returns the left-hand operand if the operand is not null; otherwise it returns the right hand operand.

If we talk about efficiency then

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

If I use a dissembler then I can see that the first statement needs 19 statements to be executed by the compiler whereas the second statement required only 12 statements to be executed.

查看更多
孤傲高冷的网名
4楼-- · 2020-05-14 05:10

No. Both are doing the same thing. Second one is efficient. Which returns the actual value if it is not null. Else the right-hand side value will be returned.

Refer this http://msdn.microsoft.com/en-us/library/ms173224.aspx

Hope this helps.

查看更多
成全新的幸福
5楼-- · 2020-05-14 05:13

Yes, they do the same. ?? is shorthand for checking for null.

查看更多
唯我独甜
6楼-- · 2020-05-14 05:17

If the property is more than a simple getter, you might be executing a function twice in the non-null case for the first one.

If the property is in a stateful object, then the second call to the property might return a different result:

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";
    }
}

Also, in the non-string case, the class might overload == to do something different than the ternary operator. I don't believe that the ternary operator can be overloaded.

查看更多
smile是对你的礼貌
7楼-- · 2020-05-14 05:22

They accomplish the same task.

Only difference would be readability as to whether your coworkers or whomever is reading the code understands the syntax.

EDIT: Additionally the first option can evaluate the property MyName twice.

查看更多
登录 后发表回答