Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.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/24.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/5/fortran/2.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# 在设置为null之前检查是否为null?_C#_.net_Null - Fatal编程技术网

C# 在设置为null之前检查是否为null?

C# 在设置为null之前检查是否为null?,c#,.net,null,C#,.net,Null,在将变量设置为null之前,我们是否应该检查它是否为null if (MyBills != null) { MyBills = null; } 例如,在一个应用程序中,性能影响是最小的。 这是C语言的情况吗?其他影响 测试 我已经创建了以下代码进行测试: var watch = System.Diagnostics.Stopwatch.StartNew(); int iterations = int.MaxValue; List<int> myBills= null;

在将变量设置为null之前,我们是否应该检查它是否为null

if (MyBills != null) 
{
    MyBills = null;
}
例如,在一个应用程序中,性能影响是最小的。 这是C语言的情况吗?其他影响

测试 我已经创建了以下代码进行测试:

var watch = System.Diagnostics.Stopwatch.StartNew();

int iterations = int.MaxValue;
List<int> myBills= null;
for (var i = 0; i < iterations; i++)
{
    if (myBills!= null)
    {
        myBills = null;
    }
}
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
Console.WriteLine(elapsedMs);

因此,即使在非受控环境中测试,性能影响也无关紧要。

不,没有太多用处。可能检查变量是否为null与多次将其设置为null一样昂贵


如果它是一个属性,后面有额外的逻辑,那么在之前测试它是有意义的,但这实际上应该是属性中的逻辑的责任,而不是您的代码。

除了property/setter参数之外,我在您提供的代码中看不到任何逻辑原因

但是,如果要在将对象设置为null之前对其执行额外操作,则有必要:

if (MyBills != null)
{
     MyBills.Dispose();
     MyBills = null;
}
或者执行一些其他操作,如记录结果

但这两个示例都不在您提供的示例代码中

因为人们似乎在质疑我的第一个例子的用例,这里有一个。这将防止多次调用Dispose导致ObjectDisposedException

我进行了一些计时,发现以下结果:

valueClass带有空检查=1361 带有空检查的nullClass=1173 valueClass不带空检查=1208 无空检查的nullClass=1148

正如您可以看到的,没有空检查,它会稍微快一点,但不足以进行任何显著的优化。此外,我在调试模式下从编译器执行了这些计时,并关闭了优化,因此它们不是100%准确/相关的

然而,当我在发布模式下运行时,在编译器外部启用了优化,结果非常接近,无论检查与否都可以忽略不计

以及测试代码:

using System;

namespace NullCheckTest
{
    class Program
    {
        const int iterations = 10000000;

        static void Main(string[] args)
        {
            MyClass valueClass = new MyClass() { Value = 10 };
            MyClass nullClass = null;

            Console.WriteLine($"valueClass with null check = {TestNullCheck(valueClass)}");
            Console.WriteLine($"nullClass with null check = {TestNullCheck(nullClass)}");

            Console.WriteLine($"valueClass with no null check = {TestNoNullCheck(valueClass)}");
            Console.WriteLine($"nullClass with no null check = {TestNoNullCheck(nullClass)}");

            Console.ReadLine();
        }

        static long TestNullCheck(MyClass myClass)
        {
            MyClass initial = myClass;

            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            for (int i = 0; i < iterations; ++i)
            {
                sw.Start();

                if (myClass != null)
                {
                    myClass = null;
                }

                sw.Stop();

                myClass = initial;
            }

            return sw.ElapsedMilliseconds;
        }

        static long TestNoNullCheck(MyClass myClass)
        {
            MyClass initial = myClass;

            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            for (int i = 0; i < iterations; ++i)
            {
                sw.Start();

                myClass = null;

                sw.Stop();

                myClass = initial;
            }

            return sw.ElapsedMilliseconds;
        }
    }

    public class MyClass
    {
        public int Value { get; set; }
    }
}

回答这个问题:不,没有必要

不过。作为一般的经验法则,对象变量和属性永远不应该为null,因为如果在某个地方设置了值,则必须始终检查代码

您应该做的是使用自定义类来指示对象变量或属性可能未初始化

像这样:

public class Maybe<T> where T : class
{
    public readonly T Value { get; }

    public Maybe(T value)
    {
        _Value = value;
    }

    public bool HasValue => _Value != null;
    public bool HasNoValue => _Value == null;

    public static operation Maybe<T>(T value) => new Maybe(value);
}
然后您可以这样使用它:

public class Foo
{
    public Maybe<Bar> Bar { get; set; }
    public int GetBarCount()
    {
        return Bar.HasValue ? Bar.Count : 0;
    }
}

public class Bar
{
    public int Count { get; set; }
}
上述代码适用于以下所有示例:

Foo foo = new Foo();
foo.Bar = new Bar(); // Outputs 0 when GetBarCount is called
foo.Bar = new Bar { Count = 2 }; // Outputs 2 when GetBarCount is called
foo.Bar = new Maybe<Bar>(new Bar()); // Outputs 0 when GetBarCount is called
foo.Bar = new Maybe<Bar>(new Bar { Count = 2 }); // Outputs 2 when GetBarCount is called
foo.Bar = new Maybe<Bar>(null); // Outputs 0 when GetBarCount is called
foo.Bar = null;  // Outputs 0 when GetBarCount is called

注意当使用Maybe时,您可以显式地将Foo.Bar标记为不总是有值,并提供一个很强的信号。但是,如果不在它上标记,则表明它总是有值的。通过在正确的位置使用Maybe包装器,代码变得更容易处理,因为您不再需要对未包装的对象变量和属性执行空检查。

当然不,为什么?您所称的变量可能是带有setter的属性,您不想运行哪种代码,然后您就可以执行此操作。我们是否应该检查。。。只有当你想处理这个案子的时候,f.e.logit@MegaTron确切地这就是问题所在。我会很感激你的评论。@MarioLevrero在你做了你的答案后,我用我的测试编辑了我的答案,所以这很好!我想在这个基础上保留它是值得的。谢谢,帕特里克。我不明白为什么会有这么多的反对者来回答这个问题。也许他们希望在提问时多付出一些努力,就像现在你链接到Java作为比较一样。你也可以做一些测试。帕特里克,我已经按照你的建议用一些测试更新了这个问题。我认为只有像你一样有建设性的批评,我们才能做出更好的S.O.再次感谢你是受欢迎的。事实上,它并不像你在测试中看到的那么重要。虽然有更好的测试方法,这将产生更准确的结果。好吧,您正在通过添加一些内容来修改OP的代码。这并不是对他的问题的真正回答。@Sinatr,这就是我的结束语。然而,它仍然是一个答案,因为它说明了这个问题的用例,而且手动调用Dispose的案例并不多。“使用在这方面更有用。@Patrickhoffman,除了在一个带有需要处理的字段的一次性类中。在我看来,这是一个常见的用例。如果一个类支持IDisposable,我将在调用时使用block来包装它。不需要设置为null。另外,如果它是一个类的实例,只需再次创建新实例。Like var mc=新的MyClass;为什么要这样混淆代码?另外,您仍然在检查null,在我看来,这个包装器类是混乱和毫无意义的。请参阅我在底部添加的注释。它应该解释得足够好。我理解你为什么这么做,我只是不明白它的意义。return Bar.HasValue有什么用?条数:0;超过返回条?计数??0;? 这造成了巨大的开销,却没有任何收益。恶心,恶心,恶心。
public class Foo
{
    public Maybe<Bar> Bar { get; set; }
    public int GetBarCount()
    {
        return Bar.HasValue ? Bar.Count : 0;
    }
}

public class Bar
{
    public int Count { get; set; }
}
Foo foo = new Foo();
foo.Bar = new Bar(); // Outputs 0 when GetBarCount is called
foo.Bar = new Bar { Count = 2 }; // Outputs 2 when GetBarCount is called
foo.Bar = new Maybe<Bar>(new Bar()); // Outputs 0 when GetBarCount is called
foo.Bar = new Maybe<Bar>(new Bar { Count = 2 }); // Outputs 2 when GetBarCount is called
foo.Bar = new Maybe<Bar>(null); // Outputs 0 when GetBarCount is called
foo.Bar = null;  // Outputs 0 when GetBarCount is called