使用 Guard 类 以简化的方式验证方法参数。 与手动编写检查和引发异常相比,此类更快、更简洁、更具表现力,且更不易出错。
工作原理
Guard这些 API 以三个核心原则为基础构建:
- 快。 为了实现此目的,所有 API 都设计为在调用方中尽可能少地生成代码,并且每个 Guard API(几乎始终)都会内联。 此外,使用 T4 模板生成专用方法,以在处理常见类型(例如基元数值类型)时实现最有效的程序集代码。
-
很有帮助。 每个
GuardAPI 都会生成一条详细的异常消息,该消息明确指定出了问题以及其他信息(例如当前变量值),如果适用。 -
直观。 为了实现这一目标,所有
GuardAPI 都有表达和自我解释的名称,使每个 API 都能够立即清楚地了解每个 API 应该执行的操作。 这将减轻编写检查的负担,让他们使用自然语言表达条件。
Syntax
以下代码片段显示了一个示例方法,其中一些检查是显式执行的,并且是手动引发语句:
public static void SampleMethod(int[] array, int index, Span<int> span, string text)
{
if (array is null)
{
throw new ArgumentNullException(nameof(array), "The array must not be null");
}
if (array.Length >= 10)
{
throw new ArgumentException($"The array must have less than 10 items, had a size of {array.Length}", nameof(array));
}
if (index < 0 || index >= array.Length)
{
throw new ArgumentOutOfRangeException(nameof(index), $"The index must be in the [0, {array.Length}) range, was {index}");
}
if (span.Length < array.Length)
{
throw new ArgumentException($"The target span is shorter than the input array, had a length of {span.Length}", nameof(span));
}
if (string.IsNullOrEmpty(text))
{
throw new ArgumentException("The input text can't be null or empty", nameof(text));
}
}
下面是相同的方法,但使用 Guard API 验证输入参数:
public static void SampleMethod(int[] array, int index, Span<int> span, string text)
{
Guard.IsNotNull(array);
Guard.HasSizeGreaterThanOrEqualTo(array, 10);
Guard.IsInRangeFor(index, array);
Guard.HasSizeLessThanOrEqualTo(array, span);
Guard.IsNotNullOrEmpty(text);
}
Guard API 以最快的方式执行所需检查,如果检查失败,则抛出包含格式良好的消息的相应异常。
注释
Guard API 依赖于[CallerArgumentExpression]自动推断要验证的参数的名称。 这需要在项目中启用 C# 10。 如果您使用较低版本的语言,则需要手动传递参数名称,例如,使用nameof()来引用它(例如,使用Guard.IsNotNull(array, nameof(array))))。
方法
类 Guard 中有几十个不同的 API 和重载。 下表介绍了其中一些内容。
概况
| 方法 | 返回类型 | 说明 |
|---|---|---|
IsNotNull<T>(T, string) |
无 (void) | 断言输入值不为 null |
IsOfType<T>(object, string) |
无 (void) | 断言输入值是特定类型 |
IsAssignableToType<T>(object, string) |
无 (void) | 断言可将输入值分配给指定类型 |
IsReferenceEqualTo<T>(T, T, string) |
无 (void) | 断言输入值必须与目标值为同一实例 |
IsTrue(bool, string) |
无 (void) | 断言输入值必须为 true |
比较
| 方法 | 返回类型 | 说明 |
|---|---|---|
IsEqualTo<T>(T, T, string) |
无 (void) | 断言输入值必须等于指定值 |
IsBitwiseEqualTo<T>(T, T, string) |
无 (void) | 断言输入值必须与指定值按位匹配 |
IsLessThan<T>(T, T, string) |
无 (void) | 断言输入值必须小于指定值 |
IsLessThanOrEqualTo<T>(T, T, string) |
无 (void) | 断言输入值必须小于或等于指定值 |
IsInRange<T>(T, T, T, string) |
无 (void) | 断言输入值必须位于 [最小值、最大值) 范围内 |
IsBetween<T>(T, T, T, string name) |
无 (void) | 断言输入值必须位于(最小值、最大值)间隔内 |
IsBetweenOrEqualTo<T>(T, T, T, string name) |
无 (void) | 断言输入值必须位于 [最小值, 最大值] 间隔中 |
字符串
| 方法 | 返回类型 | 说明 |
|---|---|---|
IsNotNullOrEmpty(string, string) |
无 (void) | 断言输入字符串实例不得为 null 或为空 |
IsNotNullOrWhiteSpace(string, string) |
无 (void) | 断言输入字符串实例不得为 null 或空格 |
收集
| 方法 | 返回类型 | 说明 |
|---|---|---|
IsNotEmpty<T>(T[], string) |
无 (void) | 断言输入数组实例不得为空 |
HasSizeEqualTo<T>(T[], int, string) |
无 (void) | 断言输入数组实例必须具有指定值的大小 |
HasSizeAtLeast<T>(T[], int, string) |
无 (void) | 断言输入数组的大小必须至少等于指定值 |
IsInRangeFor<T>(int, T[], string) |
无 (void) | 断言输入索引对给定数组有效 |
HasSizeLessThanOrEqualTo<T>(T[], T[], string) |
无 (void) | 断言源数组的大小必须小于或等于目标数组的大小 |
任务
| 方法 | 返回类型 | 说明 |
|---|---|---|
IsCompleted(Task, string) |
无 (void) | 断言输入任务处于已完成状态 |
IsNotCanceled(Task, string) |
无 (void) | 断言输入任务未取消 |
示例
可以在 单元测试中找到更多示例。