Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Nullable<;T>;。HasValue或Nullable<;T>;!=无效的_C#_.net_Null_Nullable - Fatal编程技术网

C# Nullable<;T>;。HasValue或Nullable<;T>;!=无效的

C# Nullable<;T>;。HasValue或Nullable<;T>;!=无效的,c#,.net,null,nullable,C#,.net,Null,Nullable,我总是使用Nullable.HasValue,因为我喜欢它的语义。然而,最近我正在处理其他人的现有代码库,他们使用了Nullable!=空而不是独占 是否有理由使用其中一个而不是另一个,或者这纯粹是偏好 vs 编译器用调用HasValue来替换空比较,因此没有真正的区别。只要做对您和您的同事来说更可读/更有意义的事情。我更喜欢(a!=null),以便语法与VB.Net中的引用类型匹配。。当您可以使用“.HasValue”时,不要使用“IsNotNothing”。我刚刚解决了一个“操作可能会破

我总是使用
Nullable.HasValue
,因为我喜欢它的语义。然而,最近我正在处理其他人的现有代码库,他们使用了
Nullable!=空
而不是独占

是否有理由使用其中一个而不是另一个,或者这纯粹是偏好

  • vs


  • 编译器用调用
    HasValue
    来替换空比较,因此没有真正的区别。只要做对您和您的同事来说更可读/更有意义的事情。

    我更喜欢
    (a!=null)
    ,以便语法与VB.Net中的引用类型匹配。

    。当您可以使用“.HasValue”时,不要使用“IsNotNothing”。我刚刚解决了一个“操作可能会破坏运行时稳定性”中的信任错误,在一个位置用“.HasValue”替换了“isnothing”。我真的不明白为什么,但是编译器中发生了一些不同的事情。我假设C#中的“!=null”可能也有同样的问题。

    我对此做了一些研究,使用不同的方法将值赋给可为null的int。下面是我做各种事情时发生的情况。应该澄清发生了什么。 请记住:
    Nullable
    或缩写
    something?
    是一个结构,编译器似乎在为它做大量工作,让我们像使用类一样使用null。
    如下所示,
    SomeNullable==null
    SomeNullable.HasValue
    将始终返回预期的true或false。尽管下面没有演示,
    SomeNullable==3
    也是有效的(假设SomeNullable是
    int?
    )。
    如果将
    SomeNullable.Value
    分配给
    SomeNullable
    ,则
    SomeNullable.Value
    会导致运行时错误。事实上,这是唯一一个nullables会给我们带来问题的情况,这要感谢重载运算符、重载的
    object.Equals(obj)
    方法、编译器优化和monkey business的组合

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

    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=新整数?(空),将产生编译时错误,因为可为null对象的值不可为null。只有包装器对象本身可以等于null

    类似地,我们将从以下位置获得编译时错误:

    int? val = new int?();
    val.Value = null;
    
    更不用说
    val.Value
    是一个只读属性,这意味着我们甚至不能使用以下内容:

    val.Value = 3;
    
    但同样,多形重载隐式转换运算符允许我们:

    val = 3;
    

    不必担心多义词,但只要它能正常工作,它又叫什么呢?:)

    第二种方法的效率要高得多(主要是因为编译器内联和装箱,但数字仍然非常有表现力):

    基准代码:

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

    PPS人们继续减号,似乎没有人试图预测
    CheckNullableGenericImpl
    的性能。我会告诉你:编译器不会帮你替换
    =空值
    HasValue
    <如果您对性能感兴趣,应该直接使用code>HasValue

    如果您使用linq并希望代码简短,我建议您始终使用
    =空

    这就是为什么:

    假设我们有一个类
    Foo
    ,它有一个可为空的double变量
    SomeDouble

    public class Foo
    {
        public double? SomeDouble;
        //some other properties
    }   
    
    如果在代码中的某个地方,我们希望从一个Foo集合中获取所有具有非null SomeDouble值的Foo(假设集合中的一些Foo也可以为null),那么我们至少有三种方法来编写我们的函数(如果我们使用C#6):

    public IEnumerable GetNonNullFoosWithSomeDoubleValue(IEnumerable foos)
    {
    返回foos.Where(foo=>foo?.SomeDouble!=null);
    返回foos.Where(foo=>foo?.SomeDouble.HasValue);//编译时错误
    返回foos.Where(foo=>foo?.SomeDouble.HasValue==true);
    返回foos.Where(foo=>foo!=null&&foo.SomeDouble.HasValue);//如果我们不使用C#6
    }
    

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

    我问了一个类似的问题。。。得到了一些很好的答案:就个人而言,我会使用
    HasValue
    ,因为我认为文字比符号更容易阅读。不过,这取决于您,以及什么适合您现有的样式。
    .HasValue
    更有意义,因为它表示类型是
    T?
    类型,而不是可以为null的类型,例如字符串。我想补充一点,“更一致的类型/遵循现有的编码样式。”哇。我讨厌这种糖<代码>整数?x=null让我产生一种错觉,认为可为null的实例是引用类型。但事实是Nullable是一种值类型。感觉我将得到一个NullReferenceException来执行:
    int?x=零;使用(x.HasValue)
    @KFL如果语法上的糖分让你感到困扰,就使用
    Nullable
    而不是
    int?
    。在创建应用程序的早期阶段,你可能认为使用一个Nullable value类型来存储一些数据就足够了,但过了一段时间,你才意识到你需要一个适合自己的类。编写了与null比较的原始代码,这样做的好处是,您不需要用null比较来搜索/替换对HasValue()的每个调用。抱怨能够将null设置为null或将其与null进行比较是非常愚蠢的,因为这被称为null。问题是人们把“引用类型”和“可以为空”混为一谈,但这是概念上的混乱。未来的C#将具有不可为空的引用类型。由于可读性,我更喜欢
    HasValue
    isnothing
    确实是一个丑陋的表达(因为双重否定)。@steffan“isnothing”不是双重否定。“没什么”不是否定的
    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);
        }
    }
    
    public static bool CheckNullableGenericImpl<T>(T? t) where T: struct
    {
        return t != null; // or t.HasValue?
    }
    
    public class Foo
    {
        public double? SomeDouble;
        //some other properties
    }   
    
    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
    }