在C#中检查对象是否为空


226

如果对象为null,我想防止对其进行进一步处理。

在以下代码中,我通过以下任一方法检查对象是否为空:

if (!data.Equals(null))

if (data != null)

不过,我收到NullReferenceExceptiondataList.Add(data)。如果对象为null,则它甚至都不应输入if -statement!

因此,我问这是否是检查对象是否为null的正确方法:

public List<Object> dataList;
public  bool AddData(ref Object data)
    bool success = false;
    try
    {
        // I've also used "if (data != null)" which hasn't worked either
        if (!data.Equals(null))
        {
           //NullReferenceException occurs here ...
           dataList.Add(data);
           success = doOtherStuff(data);
        }
    }
    catch (Exception e)
    {
        throw new Exception(e.ToString());
    }
    return success;
}

如果这是检查对象是否为null的正确方法,那我在做什么错(如何防止对该对象进行进一步处理以避免NullReferenceException)?


13
您还应该使用throw e;vsthrow new Exception(e.ToString());
Nix

17
在C#中,应始终!= null在null检查中使用。 .Equals如果对象为null,将始终引发异常。
Kyle Trauberman 2011年

42
@Nix:throw e;并不好。throw;,另一方面…
乔恩

4
@developer:e.ToString()将产生一个不仅包含错误消息,而且还包含所有错误消息InnerExceptions和堆栈跟踪的字符串。因此,这是一种非常繁琐的异常消息。如果您(正确!)想要保留此信息并保留它的位置,请简单地使用throw;
乔恩

14
try / catch目前不执行任何操作。每个人都说只使用“ throw”,但是如果您除了异常之外没有做任何事情,为什么还要尝试/捕获块呢?通常,您可以捕获异常以优雅地处理它们,清理资源(最好使用“ finally”子句)或在重新抛出异常之前进行某种日志记录。这些都没有发生在此代码中,因此根本不需要try / catch。
大卫·彼得森

Answers:


252

这并不是data说是null,但dataList

您需要创建一个

public List<Object> dataList = new List<Object>();

甚至更好:因为这是一个领域,所以去做吧private。而且,如果没有什么可以阻止您的,那就也做readonly。只是好的做法。

在旁边

检查无效性的正确方法是if(data != null)。对于引用类型,这种检查无处不在。甚至Nullable<T>覆盖相等运算符,这是nullable.HasValue检查空值时更方便的表达方式。

如果这样做,if(!data.Equals(null))您将得到一个NullReferenceExceptionif data == null。之所以有点可笑,是因为首先避免了此异常。

您也正在这样做:

catch (Exception e)
{
    throw new Exception(e.ToString());
}

这绝对不好。我可以想象您将其放在此处,以便可以在仍位于方法内部时进入调试器,在这种情况下,请忽略本段。否则,不要一无所获。如果这样做,请使用just将它们扔掉throw;


5
为此,我也看到了Object.ReferenceEquals(obj,null)。是否要避免平等优先?

2
@LucaPiccioni在使用泛型时,我已使用它来防止值类型的抱怨:geekality.net/2009/11/13/generics-and-checking-for-null
Svish

4
我更喜欢null != data。将常量放在首位会将首字母错字null = data变成编译器错误,而不是无意分配。(也适用于==。)
jpmc26 2014年

6
@ jpmc26:在C#if (data = null)中已经是编译时错误,因此即使花了数十年才到达目的地,我们也确实不必再为此担心了。甚至C ++编译器也很容易就该代码可能发生的意外分配发出警告。
2014年

卢卡,您还可以通过在测试中强制转换为“对象”来避免相等替代。同样,此答案应改为:“ if((object)data!= null)”,因为它避免了覆盖相等性时的错误。
DAG

81

在C#> 7.0中使用

if (obj is null) ...

这将忽略该对象定义的任何==或!=(除非您当然要使用它们...)

对于非null用途if (obj is object)(或if (!(obj is null))


1
我想知道是否存在“不为空”?(蟒蛇会说obj is not null
sehe

1
为什么这比可读性更好的if(obj!= null)好
Orn Kristjansson

38
希望他们能实现if (obj aint null):(
尼克·布尔

9
对于不为空的问题if (obj is object)
yatskovsky '19

3
@OrnKristjansson,因为!=和==可以被覆盖。
mitchellJ

61

C#6具有Monadic空检查 :)

之前:

if (points != null) {
    var next = points.FirstOrDefault();
    if (next != null && next.X != null) return next.X;
}   
return -1;

后:

var bestValue = points?.FirstOrDefault()?.X ?? -1;

7
因为“注释只能编辑5分钟”?什么?无论如何...就在我到达那里时..我来这里的目的是寻找一种更好的语法来表达,result = myObject == null ? null : myObject.SomeProperty而您的示例让我开始写作result = myObject?.SomeProperty。男子!!偷偷摸摸 我仍然喜欢编码...
Adam Cox

27

根据您发布的代码,您的dataList为空,因为尚未实例化。

尝试:

public List<Object> dataList = new List<Object>();
public  bool AddData(ref Object data)
bool success = false;
try
{
    if (!data.Equals(null))   // I've also used if(data != null) which hasn't worked either
    {
       dataList.Add(data);                      //NullReferenceException occurs here
       success = doOtherStuff(data);
    }
}
catch (Exception e)
{
    throw new Exception(e.ToString());
}
return success;

}


3
另外,只需添加,如果data为null,则不会崩溃,可以将null添加到List <Object>。
DaveShaw

7
但是尝试执行。等于null会引发异常。应该做!= null
glosrob

@glosrob:啊!真是个疏忽!我以为NullReferenceException来自对象..而不是列表!我是C#的新手,我发现有一种特殊的方法可以检查C#中的null!
开发人员

也是,但是我看到Ed S.报道了它。
DaveShaw

1
@DaveShaw:感谢大家的注意。我想避免为以后的处理添加一个空对象,因此我仍将进行检查。:)
开发人员

19

[由@ kelton52编辑以反映提示]

最简单的方法是 object.ReferenceEquals(null, data)

由于(null==data)不能保证能正常工作:

class Nully
{
    public static bool operator ==(Nully n, object o)
    {
        Console.WriteLine("Comparing '" + n + "' with '" + o + "'");
        return true;
    }
    public static bool operator !=(Nully n, object o) { return !(n==o); }
}
void Main()
{
    var data = new Nully();
    Console.WriteLine(null == data);
    Console.WriteLine(object.ReferenceEquals(null, data));
}

产生:

比较''与'Nully'

真正


1
实际上,我只是尝试过这一点,而“隐含的优势是它忽略了数据类中可能存在的任何替代,例如“ operator!=”。似乎不成立。
凯利·艾尔顿

9

不,您应该使用!=。如果data实际上为null,则您的程序将NullReferenceException由于尝试在上调用Equals方法而崩溃null。还应意识到,如果您特别想检查引用是否相等,则应使用该Object.ReferenceEquals方法,因为您永远不知道如何Equals实现。

您的程序崩溃,因为它dataList为空,因为您从未对其进行初始化。


7

在这种情况下,问题不在于data是否为空。它dataList本身就是null。

在声明的位置,您dataList应该创建一个新List对象并将其分配给变量。

List<object> dataList = new List<object>();

5

除了@Jose Ortega答案外,它更好地用于扩展方法

 public static bool IsNull(this object T)
     {
        return T == null;
     } 

并对IsNull所有对象使用方法,例如:

object foo = new object(); //or any object from any class
if (foo.IsNull())
   {
     // blah blah //
   }

1
为什么return T == null ? true : false;而不仅仅是return T == null;
md2perpe '18

1
我不确定我是否同意。在对象上调用方法以检查其是否为null看起来很奇怪。在不知道它是扩展方法的情况下,您会认为它将引发空引用异常。
Jamie Twells 18-10-17

可以完全确认Jamie是正确的-这是行不通的。我知道,因为我脑子有点呆,写了一个类似的扩展方法:P代码总是抛出空引用异常,它绝对不会进入扩展方法。
詹姆斯·金

实际上我想说的是您可以使用扩展方法来做到这一点...可能是代码有问题并且可以改善!
阿里

您可以在null对象上调用扩展方法。您只需要比较T(在这种情况下)与null即可,以防万一。杰米说得对,但是看起来很奇怪。
蒂姆·巴拉斯

3

C#8开始,您可以使用'empty'属性模式(具有模式匹配)来确保对象不为 null:

if (obj is { })
{
    // 'obj' is not null here
}

这种方法的意思是“ 如果对象引用某物的实例 ”(即它不为空)。

您可以认为这与:相反if (obj is null)...。当对象未引用某事物的实例时,它将返回true。

有关C#8.0中的模式的更多信息,请参见此处



2

杰弗里·惠特里奇(Jeffrey L Whitledge)是对的。您的“ dataList”对象本身为null。

您的代码还有另一个问题:您使用的是ref-keyword,这意味着参数数据不能为null!MSDN说:

传递给ref参数的参数必须首先初始化。这与out不同,后者的参数在传递之前不必显式初始化

将泛型与对象类型一起使用也不是一个好主意。泛型应避免装箱/拆箱,并确保类型安全。如果要使用通用类型,请使您的方法通用。最后,您的代码应如下所示:

public class Foo<T> where T : MyTypeOrInterface {

      public List<T> dataList = new List<T>();

      public bool AddData(ref T data) {
        bool success = false;
        try {
          dataList.Add(data);                   
          success = doOtherStuff(data);
        } catch (Exception e) {
          throw new Exception(e.ToString());
        }
        return success;
      }

      private bool doOtherStuff(T data) {
        //...
      }
    }

2

正如其他人已经指出,这不是data,而是有可能dataListnull。在此之上...

catch- throw是一种反模式,几乎总是让我每次看到它都想吐出来。想象一下,某些东西在doOtherStuff()调用时会出问题。您所获得的只是一个Exception扔在throwin 的物体AddData()。没有堆栈跟踪,没有调用信息,没有状态,根本没有任何东西可以指示问题的真正根源,除非您进入并切换调试器以在引发异常而不是未处理异常时中断。如果您正在捕获异常并以任何方式重新抛出该异常,尤其是在try块中的代码非同寻常的情况下,请帮自己(以及您的同事,现在和将来)帮个忙,并抛弃整个问题try - catch块。当然,throw;比替代方法要好,但是您仍然让自己(或者其他试图修复代码错误的人)完全不必要的麻烦。这并不是说try-catch-throw本身就一定是邪恶的,只要您在catch块内抛出的异常对象进行相关处理即可

Exception首先是捕获的潜在问题,但这是另一回事,尤其是在这种情况下,您会抛出异常。

令我感到不小的危险的另一件事是data,由于您是通过引用传递的,因此有可能在函数执行期间更改值。因此,空检查可能会通过,但是在代码对值进行任何处理之前,它已更改-可能更改为null。我不是很在乎这是否令人担忧(可能不是),但似乎值得提防。


2
  public static bool isnull(object T)
  {
      return T == null ? true : false;
  }

用:

isnull(object.check.it)

有条件使用:

isnull(object.check.it) ? DoWhenItsTrue : DoWhenItsFalse;

更新(另一种方式)更新了08/31/2017。感谢您的评论。

public static bool isnull(object T)
{
    return T ? true : false;
}

5
cond ? true : false;完全等同于cond。这什么也没添加。
lericson '17

抱歉,如果您检查该函数,则必须返回布尔值。我正在做形式主义。因此,重新检查
奥尔特加

3
他的意思是return T == null;还返回一个布尔值!
MQoder

我知道他在说什么。ty
Jose Ortega

1
而不是return T == null ? true : false;仅仅使用return T == null;
md2perpe

1

每当创建类的对象时,都必须使用以下代码检查对象是否为null。

示例:object1是类的对象

void myFunction(object1)
{
  if(object1!=null)
  {
     object1.value1 //If we miss the null check then here we get the Null Reference exception
  }
}

0

我只是遵循了通常在Java脚本中遵循的方法。将对象转换为字符串,然后检查它们是否为null。

var obj = new Object();
var objStr = obj.ToString();
if (!string.IsNullOrEmpty(objStr)){
  // code as per your needs
}

0

我做了更简单的(积极的方式),它似乎运作良好。

由于任何一种“对象”至少是一个对象


    if (MyObj is Object)
    {
            //Do something .... for example:  
            if (MyObj is Button)
                MyObj.Enabled = true;
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.