我经常遇到类似的架构问题。人们应该多久检查输入参数的有效性?让我们检查以下示例(不关心代码的正确性或可编译性):
public void DoSth()
{
context.DbPerform((SQLiteConnection connection) =>
{
// *** 1 ***
if (connection == null)
throw new ArgumentNullException("connection");
if (!connection.IsOpen)
connection.Open();
try
{
Data.Insert(data, connection);
}
finally
{
connection.Close();
}
});
}
// ----
public static void Insert(Data data, SQLiteConnection connection)
{
// *** 2 ***
if (data == null)
throw new ArgumentNullException("data");
if (connection == null)
throw new ArgumentNullException("connection");
if (!connection.IsOpen)
connection.Open();
try
{
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = SQL.InsertData;
FillParameters(data, connection, cmd);
cmd.ExecuteNonQuery();
}
}
finally
{
connection.Close();
}
}
// ----
public static void FillParameters(Data data,
SQLiteConnection connection,
SQLiteCommand cmd)
{
// *** 3 ***
if (connection == null)
throw new ArgumentNullException("connection");
// And so on, you get the idea
}
在上一个代码段中,已检查连接为空或关闭三次。这对我来说似乎有点过分 - 有时方法的50%是安全检查。我觉得不需要那么多的安全检查,但另一方面,其他人总是可以使用这些方法,我不能确定他是否通过了有效的参数。
所以我的问题是:
class C
{
private Obj obj;
public C (Obj newObj)
{
if (newObj == null)
throw new ArgumentNullException("newObj");
obj = newObj;
}
public void DoSth()
{
// Should I check, whether obj is not null?
}
}
答案 0 :(得分:3)
关于第一个示例,Insert()
中的检查是个好主意,因为Insert()
是public
。它可以从没有进行检查的另一个上下文中调用。
通常,始终在公共接口点进行验证。这有助于使代码松散耦合并可重用。
每一层(层,方法)都有自己的要求。因此,在该任务开始时验证您执行某项任务所需的内容。
答案 1 :(得分:1)
我同意Henk。此外,请尝试考虑Visual Studio的Code Contracts扩展,它提供了一种在代码中指定前置条件,后置条件和对象不变量的方法:http://visualstudiogallery.msdn.microsoft.com/1ec7db13-3363-46c9-851f-1ce455f66970。它强制执行一种非常一致的方法来保护您的代码,并且“Pex”工具可用于根据合同自动生成测试。