在哪里检查传递给方法的对象是否为空?
在调用方法之前是否需要测试对象?或者在使用参数的方法中?
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。我想知道这是否是一种被广泛接受的做法。
答案 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
开始时,这将强制您通过调用堆栈进行检查。
层次结构中的较低功能是应该执行的检查较少。以下是在执行工作的函数中执行检查的缺点。
答案 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)
正如我理解你的问题,它比你的例子更为通用。我的偏好如下:
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)
由于两个原因,我更喜欢方法内部的空检查。
我认为函数应该是“完整的”,即处理空值/“边缘情况”,而不依赖于调用者。这有两个原因,
该方法内部具有null检查,可减少代码内部的null检查总数,这通常意味着代码可读性更高