C# class 构造函数前置条件
C# class constructor precondition
假设我有一个 class,带有构造函数
public RepresentativeService(IUserContext userContext, INavServiceClient navServiceClient)
{
_userContext = userContext;
_navServiceClient = navServiceClient;
}
我想添加前提条件
if (userContext == null) throw new ArgumentNullException(nameof(userContext));
if (navServiceClient == null) throw new ArgumentNullException(nameof(navServiceClient));
if (string.IsNullOrEmpty(userContext.CustomerNumber)) throw new ArgumentNullException(nameof(userContext.CustomerNumber));
if (string.IsNullOrEmpty(userContext.PersonalCode)) throw new ArgumentNullException(nameof(userContext.PersonalCode));
确保服务方法正常工作。此外,向方法添加条件是没有意义的,例如
public void Appoint(PrivatePerson person)
不应检查 userContext 是否为空或它需要的某个值是否为 String.Empty。向构造函数添加先决条件可能是一个糟糕的决定,但另一方面它会很快失败并给出正确的精确错误。
Service只是webservice的一个门面,来自第三方。在没有先决条件的情况下,我允许用户说出类似:"remove representative with null id" 的内容,这似乎不正确。如果我不添加它们,那么为它们添加 unit/integration 测试也没有意义。
我的问题是:我应该添加前提条件吗?在哪里添加?
在构造函数中添加前提条件通常是个好主意。您正在保护您的不变量。您不希望有人以不良状态实例化您的 class。例如,当某物不能为 null 时,它为 null。您还应该向在方法的上下文中有意义的方法添加前提条件。在您的示例中,检查 person 是否为 null。
public void Appoint(PrivatePerson person)
{
if (person == null)
{
throw new ArgumentNullException(nameof(person));
}
// code
}
这也叫防御性编程。您假设代码的调用者向您传递了不寻常的参数,因此您检查代码中是否存在无效参数。这是很好的做法。
关于测试,您应该在单元测试中测试您的先决条件。您的先决条件是代码执行流程的一部分。如果您不在测试中使用它们,您将无法确定它们是否按预期工作。
总而言之,在任何你想保证正确的对象状态的地方添加前提条件,这通常无处不在。
在构造函数中添加前置条件实际上很常见。哎呀,它甚至被我们使用和喜爱的 CLR 类 使用!
例如,如果你反编译 System.Linq.OrderedEnumerable
你会发现这个构造函数:
internal OrderedEnumerable(IEnumerable<TElement> source, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
if (source == null)
throw Error.ArgumentNull("source");
if (keySelector == null)
throw Error.ArgumentNull("keySelector");
this.source = source;
this.parent = (OrderedEnumerable<TElement>) null;
this.keySelector = keySelector;
this.comparer = comparer != null ? comparer : (IComparer<TKey>) Comparer<TKey>.Default;
this.descending = descending;
}
假设我有一个 class,带有构造函数
public RepresentativeService(IUserContext userContext, INavServiceClient navServiceClient)
{
_userContext = userContext;
_navServiceClient = navServiceClient;
}
我想添加前提条件
if (userContext == null) throw new ArgumentNullException(nameof(userContext));
if (navServiceClient == null) throw new ArgumentNullException(nameof(navServiceClient));
if (string.IsNullOrEmpty(userContext.CustomerNumber)) throw new ArgumentNullException(nameof(userContext.CustomerNumber));
if (string.IsNullOrEmpty(userContext.PersonalCode)) throw new ArgumentNullException(nameof(userContext.PersonalCode));
确保服务方法正常工作。此外,向方法添加条件是没有意义的,例如
public void Appoint(PrivatePerson person)
不应检查 userContext 是否为空或它需要的某个值是否为 String.Empty。向构造函数添加先决条件可能是一个糟糕的决定,但另一方面它会很快失败并给出正确的精确错误。
Service只是webservice的一个门面,来自第三方。在没有先决条件的情况下,我允许用户说出类似:"remove representative with null id" 的内容,这似乎不正确。如果我不添加它们,那么为它们添加 unit/integration 测试也没有意义。
我的问题是:我应该添加前提条件吗?在哪里添加?
在构造函数中添加前提条件通常是个好主意。您正在保护您的不变量。您不希望有人以不良状态实例化您的 class。例如,当某物不能为 null 时,它为 null。您还应该向在方法的上下文中有意义的方法添加前提条件。在您的示例中,检查 person 是否为 null。
public void Appoint(PrivatePerson person)
{
if (person == null)
{
throw new ArgumentNullException(nameof(person));
}
// code
}
这也叫防御性编程。您假设代码的调用者向您传递了不寻常的参数,因此您检查代码中是否存在无效参数。这是很好的做法。
关于测试,您应该在单元测试中测试您的先决条件。您的先决条件是代码执行流程的一部分。如果您不在测试中使用它们,您将无法确定它们是否按预期工作。
总而言之,在任何你想保证正确的对象状态的地方添加前提条件,这通常无处不在。
在构造函数中添加前置条件实际上很常见。哎呀,它甚至被我们使用和喜爱的 CLR 类 使用!
例如,如果你反编译 System.Linq.OrderedEnumerable
你会发现这个构造函数:
internal OrderedEnumerable(IEnumerable<TElement> source, Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
if (source == null)
throw Error.ArgumentNull("source");
if (keySelector == null)
throw Error.ArgumentNull("keySelector");
this.source = source;
this.parent = (OrderedEnumerable<TElement>) null;
this.keySelector = keySelector;
this.comparer = comparer != null ? comparer : (IComparer<TKey>) Comparer<TKey>.Default;
this.descending = descending;
}