开发者

What's better: id ?? 0 == 0 or id == null || id == 0?

Since I have

public class Foo
{
  public int? Id { get; set; }
}

What's better

if ((Id ?? 0) == 0) {}开发者_高级运维

or

if (Id == null || Id == 0)

?


I recommend second one. It is more readable.

And as I have noticed, less people are familiar with ?? operator.


if(Id.GetValueOrDefault() == 0)

Is also an option. In terms of performance, I doubt that there is any real difference, and in any case you would be doing micro-optimization, which is rarely beneficial.


I prefer readability over cleverness (almost) every time, so I definitely go with: if (Id == null || Id == 0)


Even better would be:

   if(!Id.HasValue || Id == 0)
   {
   }


Since this is tagged "performance", here's my general advice on such topics, which I still think is valid here:

  1. Measure, measure, measure
  2. Don't micro-optimize unless it's the last thing you can do, and still need to get a few cycles out of a core loop

To expand:

There could very well be things present in your code that makes such micro-optimization tips invalid or non-optimal, so your best option regarding performance is just to measure it. Make sure you measure enough iterations of a loop as measuring that small code 1 time is going to get disturbed by all the other things your machine does invalidating the whole excercise.

As for micro-optimizations, don't worry about it. Pick the one you (and whoever else is going to maintain the code) is most comfortable with, and worry about micro-optimizations if, and when, you actually need to.

Personally I often write the first, ie.

if (o ?? 0 == 0)

or, in the case of strings:

if ((s ?? string.Empty).Length == 0)

However, in terms of readability and "what looks best", this is a bikeshed problem. Go with what you want yourself and feel comfortable with, and move on to bigger issues.

Edit, Ok, I stopped thinking somewhere before that last code example. I combined two different things I do:

  1. I never leave string properties and fields as null unless that is useful
  2. Since 1. I can do if (PropertyName.Length == 0)

Of course, in that particular example I would use either of the following two:

  1. if (string.IsNullOrEmpty(s))
  2. if (string.IsNullOrWhiteSpace(s)) (only in 4.0, and only if you need to)


If you are using this code one time, it's not quite big difference what to use (but, I'd prefer second one - it's more readable). Otherwise, I'd like to give some name of condition that I verify here. E.g.

public class Foo
{
  public int? Id { get; set; }

  public bool IsNew
  {
    get
    {
        return (Id == null) || (Id == 0);
    }
  }
}

Now code says what you are verifying. And it's readable as a book

if (IsNew) {}


I reckon that in your case the first example could be fractionally quicker.

I did this both ways in LinqPad

void Main()
{
    Foo f = new Foo();
    if ((Id ?? 0) == 0) {} // if (f.Id == null || f.Id == 0) {}
}

// Define other methods and classes here
public class Foo
{
  public int? Id { get; set; }
}

The IL for if ((Id ?? 0) == 0) {} is as follows:

IL_0000:  newobj      UserQuery+Foo..ctor
IL_0005:  stloc.0     
IL_0006:  ldloc.0     
IL_0007:  callvirt    UserQuery+Foo.get_Id
IL_000C:  stloc.1     
IL_000D:  ldloca.s    01 
IL_000F:  call        System.Nullable<System.Int32>.get_HasValue
IL_0014:  brtrue.s    IL_0019
IL_0016:  ldc.i4.0    
IL_0017:  br.s        IL_0020
IL_0019:  ldloca.s    01 
IL_001B:  call        System.Nullable<System.Int32>.GetValueOrDefault

Foo.get_Id:
IL_0000:  ldarg.0     
IL_0001:  ldfld       UserQuery+Foo.<Id>k__BackingField
IL_0006:  ret         

Foo.set_Id:
IL_0000:  ldarg.0     
IL_0001:  ldarg.1     
IL_0002:  stfld       UserQuery+Foo.<Id>k__BackingField
IL_0007:  ret         

Foo..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        System.Object..ctor
IL_0006:  ret    

THE IL for if (f.Id == null || f.Id == 0) is below - note two calls to get_HasValue

IL_0000:  newobj      UserQuery+Foo..ctor
IL_0005:  stloc.0     
IL_0006:  ldloc.0     
IL_0007:  callvirt    UserQuery+Foo.get_Id
IL_000C:  stloc.1     
IL_000D:  ldloca.s    01 
IL_000F:  call        System.Nullable<System.Int32>.get_HasValue
IL_0014:  brfalse.s   IL_0031
IL_0016:  ldloc.0     
IL_0017:  callvirt    UserQuery+Foo.get_Id
IL_001C:  stloc.2     
IL_001D:  ldloca.s    02 
IL_001F:  call        System.Nullable<System.Int32>.GetValueOrDefault
IL_0024:  brtrue.s    IL_002F
IL_0026:  ldloca.s    02 
IL_0028:  call        System.Nullable<System.Int32>.get_HasValue
IL_002D:  br.s        IL_0030
IL_002F:  ldc.i4.0    

Foo.get_Id:
IL_0000:  ldarg.0     
IL_0001:  ldfld       UserQuery+Foo.<Id>k__BackingField
IL_0006:  ret         

Foo.set_Id:
IL_0000:  ldarg.0     
IL_0001:  ldarg.1     
IL_0002:  stfld       UserQuery+Foo.<Id>k__BackingField
IL_0007:  ret         

Foo..ctor:
IL_0000:  ldarg.0     
IL_0001:  call        System.Object..ctor
IL_0006:  ret         

Maybe I should get out more!


I do recommand the second one also the code should preferrably like following

 if (null == Id || 0 == Id)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜