代码之家  ›  专栏  ›  技术社区  ›  lc.

首选:nullable<>.hasValue或nullable<>!= NULL?

  •  368
  • lc.  · 技术社区  · 15 年前

    我总是用(a) Nullable<>.HasValue 因为我喜欢语义学。然而,最近我正在研究别人使用的现有代码库(B) Nullable<> != null 相反,它是唯一的。是否有理由使用其中一个而不是另一个,或者它纯粹是偏好?

    (a)

    int? a;
    if (a.HasValue)
        ...
    

    (b)

    int? b;
    if (b != null)
        ...
    
    6 回复  |  直到 6 年前
        1
  •  401
  •   Rex M    15 年前

    编译器将空比较替换为对 HasValue 所以没有真正的区别。只要做你和你的同事更易读/更有意义的事情。

        2
  •  41
  •   Roman Marusyk S Kotra    7 年前

    我更喜欢 (a != null) 以便语法与引用类型匹配。

        3
  •  19
  •   Perrin Larson    8 年前

    我用不同的方法为一个可以为空的int赋值,对此做了一些研究。下面是我做各种事情时发生的事情。应该弄清楚发生了什么。 记住: Nullable<something> 或者速记 something? 是一个结构,编译器似乎为它做了很多工作,让我们像使用类一样使用null。
    正如你在下面看到的, SomeNullable == null SomeNullable.HasValue 将始终返回预期的“真”或“假”。虽然下面没有演示, SomeNullable == 3 也是有效的(假设someNullable是 int? )
    同时 SomeNullable.Value 如果我们分配了运行时错误 null SomeNullable .实际上,这是唯一一种情况,在这种情况下,由于重载运算符的组合,nullables可能会导致我们出现问题 object.Equals(obj) 方法,以及编译器优化和Monkey业务。

    下面是我运行的一些代码的描述,以及它在标签中生成的输出:

    int? val = null;
    lbl_Val.Text = val.ToString(); //Produced an empty string.
    lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
    lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
    lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
    lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
    lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
    lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
    lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
    

    好,让我们尝试下一个初始化方法:

    int? val = new int?();
    lbl_Val.Text = val.ToString(); //Produced an empty string.
    lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
    lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
    lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
    lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
    lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
    lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
    lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
    

    和以前一样。请记住,初始化时使用 int? val = new int?(null); 如果将空值传递给构造函数,则会产生编译时错误,因为可为空的对象的值不可为空。只有包装对象本身可以等于空。

    同样,我们将从以下位置得到编译时错误:

    int? val = new int?();
    val.Value = null;
    

    更不用说了 val.Value 无论如何都是只读属性,这意味着我们甚至不能使用以下内容:

    val.Value = 3;
    

    但是,多形重载隐式转换运算符让我们可以这样做:

    val = 3;
    

    不必担心一词多义,不过,只要它正确就行了。:)

        4
  •  14
  •   Carter Medlin    14 年前

    在VB.Net。如果可以使用“.hasValue”,请不要使用“isnot nothing”。我刚刚解决了一个“操作可能会破坏运行时”中的信任错误,将“isnot nothing”替换为“.hasValue”。我真的不明白为什么,但是编译器中发生了不同的事情。我假设“!C中的“=null”可能有相同的问题。

        5
  •  1
  •   yan yankelevich    6 年前

    如果您使用LINQ并且希望保持代码简短,我建议您始终使用 !=null

    这就是为什么:

    想象一下我们有课 Foo 用一个 可空双 变量 SomeDouble

    public class Foo
    {
        public double? SomeDouble;
        //some other properties
    }   
    

    如果在我们的代码中的某个地方,我们希望从foo集合中获取具有非空somedouble值的所有foo(假设集合中的某些foo也可以为空),那么最后我们至少有三种方法来编写函数(如果我们使用c 6):

    public IEnumerable<Foo> GetNonNullFoosWithSomeDoubleValues(IEnumerable<Foo> foos)
    {
         return foos.Where(foo => foo?.SomeDouble != null);
         return foos.Where(foo=>foo?.SomeDouble.HasValue); // compile time error
         return foos.Where(foo=>foo?.SomeDouble.HasValue == true); 
         return foos.Where(foo=>foo != null && foo.SomeDouble.HasValue); //if we don't use C#6
    }
    

    在这种情况下,我建议总是选择短一点的

        6
  •  -6
  •   Roman Pokrovskij Peterdk    6 年前

    一般答案和经验法则:如果您有一个选项(例如,编写自定义序列化程序)来处理可在不同管道中为空的 object -并使用它们的特定属性-执行该操作并使用可为空的特定属性。 所以从一致的思维角度来看 HasValue 应优先考虑。一致的思想可以帮助您编写更好的代码,不要在细节上花费太多时间。 例如,第二种方法的效率要高出许多倍(主要是因为编译器的内联和装箱,但数字仍然很有表现力):

    public static bool CheckObjectImpl(object o)
    {
        return o != null;
    }
    
    public static bool CheckNullableImpl<T>(T? o) where T: struct
    {
        return o.HasValue;
    }
    

    基准测试:

    BenchmarkDotNet=v0.10.5, OS=Windows 10.0.14393
    Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
    Frequency=3233539 Hz, Resolution=309.2587 ns, Timer=TSC
      [Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1648.0
      Clr    : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1648.0
      Core   : .NET Core 4.6.25009.03, 64bit RyuJIT
    
    
            Method |  Job | Runtime |       Mean |     Error |    StdDev |        Min |        Max |     Median | Rank |  Gen 0 | Allocated |
    -------------- |----- |-------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|-----:|-------:|----------:|
       CheckObject |  Clr |     Clr | 80.6416 ns | 1.1983 ns | 1.0622 ns | 79.5528 ns | 83.0417 ns | 80.1797 ns |    3 | 0.0060 |      24 B |
     CheckNullable |  Clr |     Clr |  0.0029 ns | 0.0088 ns | 0.0082 ns |  0.0000 ns |  0.0315 ns |  0.0000 ns |    1 |      - |       0 B |
       CheckObject | Core |    Core | 77.2614 ns | 0.5703 ns | 0.4763 ns | 76.4205 ns | 77.9400 ns | 77.3586 ns |    2 | 0.0060 |      24 B |
     CheckNullable | Core |    Core |  0.0007 ns | 0.0021 ns | 0.0016 ns |  0.0000 ns |  0.0054 ns |  0.0000 ns |    1 |      - |       0 B |
    

    基准代码:

    public class BenchmarkNullableCheck
    {
        static int? x = (new Random()).Next();
    
        public static bool CheckObjectImpl(object o)
        {
            return o != null;
        }
    
        public static bool CheckNullableImpl<T>(T? o) where T: struct
        {
            return o.HasValue;
        }
    
        [Benchmark]
        public bool CheckObject()
        {
            return CheckObjectImpl(x);
        }
    
        [Benchmark]
        public bool CheckNullable()
        {
            return CheckNullableImpl(x);
        }
    }
    

    https://github.com/dotnet/BenchmarkDotNet 被使用

    聚苯乙烯 .人们说,建议“因为始终如一的思考而偏爱有价值”是不相关的和无用的。 你能预测这个的性能吗?

    public static bool CheckNullableGenericImpl<T>(T? t) where T: struct
    {
        return t != null;
    }
    

    聚苯硫醚 人们继续减负,但没有人试图预测 CheckNullableGenericImpl . 编译器也不会帮你替换 !=null 具有 哈斯值 . 哈斯值 如果您对性能感兴趣,应该直接使用。