在设置为null之前,请检查null是否为空



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

if (MyBills != null) 
{
    MyBills = null;
}
例如,例如,在与Java相关的问题中,性能含义最小。在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);

在有和没有if (myList != null)的情况下,在Rextester上运行它的结果如下:

With check      Without check
988             941
938             1021
953             987
998             973
1004            1031
Average 
976.2           990.6

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

不,没有太多用途。可能检查变量 null是否昂贵,就像将其设置为一个零一次。

如果是属性,背后有其他逻辑,则以前进行测试是有意义的,但这实际上应该是属性中逻辑的责任,而不是您的代码。<<<<<<<<<<<<<<<<<</p>

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

但是,如果要在对象设置为null之前对对象进行额外操作,则是有道理的:

if (MyBills != null)
{
     MyBills.Dispose();
     MyBills = null;
}

或执行其他操作,例如记录结果。

,但这两个示例都超出了您提供的示例代码。


因为人们似乎在我的第一个示例中质疑用例,所以这是一个。这将防止多次呼叫Dispose引起ObjectDisposedException

public class MyClass : IDisposable
{
    private SomeDisposableObject _disposableObject;
    //Some code
    public void Dispose()
    {
        if (_disposableObject != null)
        {
            _disposableObject.Dispose();
            _disposableObject = null;
        }
    }
}

我执行了一些时间,并找到了以下结果:

带有零检查的ValueClass = 1361
无效检查= 1173
nullClass 无零检查= 1208
的ValueClass
无零检查= 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,因为它迫使您始终必须检查代码。

您应该做的是使用自定义类Maybe<>表明可能不会初始化对象变量或属性。

喜欢:

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<Bar>时,您会明确标记Foo.Bar并不总是具有值,并提供强烈的信号。但是,不用Maybe<Bar>标记它,而是信号表明它将始终具有一个值。通过在正确的位置使用Maybe<>包装器,代码变得更加容易使用,因为您不必再进行 null 检查未包装的对象变量和属性。

相关内容

  • 没有找到相关文章

最新更新