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

dan*_*die 18 .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; }
}
Run Code Online (Sandbox Code Playgroud)

在两个类中进行"空"检查似乎是太多的冗余代码.

[编辑]:在调用者或被调用者中检查空值会有什么好处?

[编辑方面2]:我刚刚遇到防御性编程,似乎它主张在被调用者中检查null.我想知道这是否是一种被广泛接受的做法.

Dan*_*ner 8

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

                    --------------------------
                   |                          |
                   |         Library          |
                   |                          |
 -------        ---------        ----------   |
|       |      |         |      |          |  |
| Outer |      | Library |      | Library  |  |
|       | ===> | Entry   | ===> | Backend/ |  |
| World |      | Method  |      | Helpers  |  |
|       |      |         |      |          |  |
 -------        ---------        ----------   |
                   |                          |
                   |                          |
                    --------------------------
Run Code Online (Sandbox Code Playgroud)

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

UPDATE

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

private CallingMethod()
{
   CalledMethod(someData);
}

private CalledMethod(Object parameter)
{
   if (parameter == null)
   {
      // Do something
   }
   else
   {
      // Do something else
   }
}
Run Code Online (Sandbox Code Playgroud)

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

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

private CalledMethod(Object parameter)
{
   // Do something
}
Run Code Online (Sandbox Code Playgroud)

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


Jon*_*eet 6

你没有什么可以检查Main- 你使用的new运算符永远不会返回null(除了Nullable<T>).

办理登机手续是完全合理的PrintAge,特别是如果公开的话.(对于私有API,进行参数检查并不重要,但它仍然非常有用.)

if (person == null)
{
    throw new ArgumentNullException("person");
}
Run Code Online (Sandbox Code Playgroud)

现在在C#3.0中,我通常使用扩展方法.


Myk*_*yev 4

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

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

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

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

Debug.Assert( Person );
Run Code Online (Sandbox Code Playgroud)

PrintAge开始时,这将迫使您通过调用堆栈进行上部检查。

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

  • 执行实际工作的函数必须尽可能清晰,且不包含大量if语句
  • 函数将被调用多次
  • 这样的函数可以调用这样的函数,并且它们可以再次调用这样的函数。他们每个人都会执行相同的验证

  • Debug.Assert 的问题在于,除非您在发布版本中显式包含 DEBUG 符号,否则您的代码在开发和生产中的行为会有所不同 - 不好。生产是你想要*真正*确保你不会继续使用坏数据的时间:) (3认同)