在哪里检查对象是否为空?

时间:2009-04-01 16:06:09

标签: .net null

在哪里检查传递给方法的对象是否为空?

在调用方法之前是否需要测试对象?或者在使用参数的方法中?

public class Program
{
    public static void Main(string[] args)
    {
        // Check if person is null here? or within PrintAge?

        PrintAge(new Person { Age = 1 });
    }

    private static void PrintAge(Person person)
    {
        // check if person is null here?

        Console.WriteLine("Age = {0}", person.Age);
    }
}

public class Person
{
    public int Age { get; set; }
}

在两个类中进行“null”检查似乎是冗余的代码。

[编辑] :在调用者或被调用者中检查null会有什么不利?

[EDIT2] :我刚刚遇到Defensive Programming,似乎主张在被叫方中检查null。我想知道这是否是一种被广泛接受的做法。

13 个答案:

答案 0 :(得分:8)

如果您设计了一个库,那么将有一些方法暴露给外部世界。您应该检查此方法中的传入数据。在您不公开的方法中不需要检查,因为只有您的代码调用它们,并且它的逻辑应该处理您在被调用的公开方法中接受的所有情况。

                    --------------------------
                   |                          |
                   |         Library          |
                   |                          |
 -------        ---------        ----------   |
|       |      |         |      |          |  |
| Outer |      | Library |      | Library  |  |
|       | ===> | Entry   | ===> | Backend/ |  |
| World |      | Method  |      | Helpers  |  |
|       |      |         |      |          |  |
 -------        ---------        ----------   |
                   |                          |
                   |                          |
                    --------------------------

如果您已在条目方法中接受了提供的数据,则应执行请求的操作并返回预期结果,即处理所有剩余案例。

<强>更新

清除库内的情况。可能存在空检查,但仅仅是因为逻辑,而不是因为参数验证。在库内部进行空检查的位置有两种可能性。如果被调用的方法知道如何处理空值,则第一个。

private CallingMethod()
{
   CalledMethod(someData);
}

private CalledMethod(Object parameter)
{
   if (parameter == null)
   {
      // Do something
   }
   else
   {
      // Do something else
   }
}

第二种情况,如果你调用一个无法处理空值的方法。

private CallingMethod()
{
   if (someData == null)
   {
      // Do the work myself or call another method
   }
   else
   {
      CalledMethod(someData);
   }
}

private CalledMethod(Object parameter)
{
   // Do something
}

整个想法是拒绝你无法处理的案件并妥善处理所有剩余案件。如果输入无效,则抛出异常。这会强制库调用程序仅提供有效值,并且不允许调用者继续使用无意义的返回值执行(除了调用者浅化异常并继续)。

答案 1 :(得分:6)

您无需查看Main - 您正在使用永不返回null的new运算符(Nullable<T>除外)。

签入PrintAge是完全合理的,特别是如果它是公开的。 (对于私有API,进行参数检查并不重要,但它仍然非常有用。)

if (person == null)
{
    throw new ArgumentNullException("person");
}

现在在C#3.0中,我通常use an extension method for this

答案 2 :(得分:4)

我会说检查它在PrintAge似乎更有意义,因为它正在履行例程的合同。当然,您可以使用Debug.Assert()代码替换空检查以在测试时检查,但不能在发布时检查。

答案 3 :(得分:3)

您可以设计一种仅使用有效对象的方法。

这意味着您希望收到有效的对象(在您的情况下不为空) 这意味着您不知道如何应对以及如何处理无效对象:

  • 从函数中静默返回 不是解决方案;
  • 抛出异常意味着你将责任移到上层 他们可以在传递给你之前检查价值的方法。

因此,如果您的方法不确切知道如何处理无效对象,并且该方法不会在无效情况下遵循其他逻辑,则应该放

Debug.Assert( Person );

PrintAge开始时,这将强制您通过调用堆栈进行检查

层次结构中的较低功能是应该执行的检查较少。以下是在执行工作的函数中执行检查的缺点

  • 正在进行实际工作的功能 必须尽可能清楚 没有大量 if s
  • 函数将被多次调用
  • 这样的功能可以调用这些功能,并且可以再次调用这些功能。他们每个人都将执行相同的验证

答案 4 :(得分:2)

你的意思是检查这两种方法?我肯定会检查PrintAge,如果在Main内部也是有意义的话。我认为一般没有明确的答案。这取决于: - )

答案 5 :(得分:2)

我通常会让我的空值检查受到我的期望的控制;如果我希望某些内容为空或不确定,我会添加一张支票。否则我没有。 Nulllpointer异常是最容易跟踪的问题之一,因此过多的支票会使代码膨胀。在具体的例子中,我什么都没检查,因为它是直觉的,它不是空的。

答案 6 :(得分:1)

如果实例为空,您想要做什么?

我认为这取决于您提供的API&amp;定义契约(.net框架类的方式)。话虽如此,你不需要检查null(在main中),如果方法定义了传递给它的空引用的预期结果。

答案 7 :(得分:1)

只有一次构造函数可以在new()]上返回null [Nullable<T> - 所以调用代码不需要检查。

被叫方可能应该检查;如果它为null,则抛出ArgumentNullException。在.NET 4.0中,代码契约可以更好地满足这一要求。但还没有;-p

答案 8 :(得分:1)

正如我理解你的问题,它比你的例子更为通用。我的偏好如下:

  • 所有可公开访问的方法都必须检查NULL输入并根据需要抛出异常。因此,如果您正在构建供其他人使用的框架,请进行防御性编码。
  • 私有方法可能会省略NULL检查,如果你知道这是在别处完成的,或者参数永远不会是NULL,但一般来说我更喜欢显式的ArgumentNullException到NullRefereceException。

Brad Abrams在这里有更多的输入:http://blogs.msdn.com/brada/archive/2004/07/11/180315.aspx

答案 9 :(得分:0)

冗余代码不是最优雅但是安全。

这取决于您的目标用户是谁,如果是您,那么您可以控制所有内容的使用方式,只有在您不确定变量的状态时才需要进行检查。

如果您让其他人使用,那么空检查可能是个好主意。即使你只是抛出一个NullPointerException,最好快速失败。

答案 10 :(得分:0)

绝对检查PrintAge,这是一个正确的检查位置。它可能是多余的,但除非你每秒执行1000次,否则不会伤害任何人。 (根据检查抛出异常或修复它,如果可以的话)

其他检查取决于您的实际流量,在此示例中您没有流量,因此我无法评论该位。但通常认为你的参数是污染的。

答案 11 :(得分:0)

PrintAge应该是Person上的方法,而不是以Person作为参数的静态方法。不需要检查。

检查空值会使代码变得不必要地复杂化。构造代码以限制(或消除)null为可能值的情况,并且您将要编写的检查更少。

答案 12 :(得分:0)

由于两个原因,我更喜欢方法内部的空检查。

  1. 我认为函数应该是“完整的”,即处理空值/“边缘情况”,而不依赖于调用者。这有两个原因,

    • 稍后调用该方法的人可能会忘记添加空检查
    • 在单元测试中使用边缘案例测试方法更加容易。
  2. 该方法内部具有null检查,可减少代码内部的null检查总数,这通常意味着代码可读性更高