给它一个星标 ⭐!
喜欢它吗?通过给这个项目一个星标来表示你的支持!
可空类型与非空类型
这个库设计时考虑了启用可空引用类型特性的情况。
Throw()
方法是所有非空类型的入口方法:
string name = "hello";
name.Throw().IfLongerThan(10);
而 ThrowIfNull()
用于任何可空类型:
string? name = "hello";
name.ThrowIfNull();
尝试在可空类型上使用 Throw()
将会给出警告
string? name = null;
name.Throw() // 警告 CS8714:类型"string?"不能用作泛型类型或方法"ValidatableCreationExtensions.Throw<TValue>(TValue, ExceptionCustomizations?, string?)"中的类型参数"TValue"。类型参数"string?"的可空性与"notnull"约束不匹配。
.IfEmpty();
在验证可空类型不为 null 后,可以使用所有常规的非空规则
name.ThrowIfNull()
.IfEmpty()
.IfLongerThan(3);
表达式可以隐式转换为原始可空类型的非空类型
string? name = "Amichai";
string nonNullableName = name.ThrowIfNull()
.IfEmpty()
.IfLongerThan(10);
或者
int? a = 5;
int b = a.ThrowIfNull();
自定义一切
自定义异常如何影响链式规则
如果你已经自定义了异常,任何抛出异常的规则都将使用该自定义。例如:
// 默认行为:
name.Throw()
.IfEmpty() // System.ArgumentException:字符串不应为空。(参数"name")
.IfWhiteSpace() // System.ArgumentException:字符串不应仅包含空白字符。(参数"name")
.IfLongerThan(3) // System.ArgumentException:字符串长度不应超过 3 个字符。(参数"name")
.IfShorterThan(10); // System.ArgumentException:字符串长度不应少于 10 个字符。(参数"name")
// 自定义行为:
name.Throw(paramName => throw new MyCustomException($"参数名称:{paramName}。"))
.IfEmpty() // MyCustomException:参数名称:name。
.IfWhiteSpace() // MyCustomException:参数名称:name。
.IfLongerThan(3) // MyCustomException:参数名称:name。
.IfShorterThan(10); // MyCustomException:参数名称:name。
你可以随时更改异常自定义,它将应用于之后的所有规则。例如:
name.Throw("字符串不应为空或仅包含空白字符。")
.IfEmpty() // System.ArgumentException:字符串不应为空或仅包含空白字符。(参数"name")
.IfWhiteSpace() // System.ArgumentException:字符串不应为空或仅包含空白字符。(参数"name")
.Throw("字符串长度不应在 3 到 10 个字符之间。")
.IfLongerThan(3) // System.ArgumentException:字符串长度不应在 3 到 10 个字符之间。(参数"name")
.IfShorterThan(10); // System.ArgumentException:字符串长度不应在 3 到 10 个字符之间。(参数"name")
要返回默认异常,只需使用 Throw()
方法。例如:
name.Throw("字符串不应为空或仅包含空白字符。")
.IfEmpty() // System.ArgumentException:字符串不应为空或仅包含空白字符。(参数"name")
.IfWhiteSpace() // System.ArgumentException:字符串不应为空或仅包含空白字符。(参数"name")
.Throw()
.IfLongerThan(3) // System.ArgumentException:字符串长度不应超过 3 个字符。(参数"name")
.IfShorterThan(10); // System.ArgumentException:字符串长度不应少于 10 个字符。(参数"name")
异常自定义
1. Throw()
每个规则都有默认行为。如果你不自定义异常,将使用默认行为。
使用 Throw()
或 ThrowIfNull()
方法抛出默认异常
// ArgumentNullException:值不能为 null。(参数"nullableValue")
nullableValue.ThrowIfNull();
// System.ArgumentOutOfRangeException:值不应小于 2042/2/28 16:41:46。(参数"dateTime")\n 实际值为 2022/2/28 16:41:46。
dateTime.Throw().IfLessThan(DateTime.Now.AddYears(20));
// ArgumentException:值不应为 true(参数"isGood")
isGood.Throw().IfTrue();
// System.ArgumentException:字符串不应为空。(参数"name")
name.Throw().IfEmpty();
// System.ArgumentOutOfRangeException:值不应大于 0。(参数"number")\n 实际值为 5。
number.Throw().IfPositive();
2. Throw("我的自定义消息")
向 Throw()
或 ThrowIfNull()
方法传递自定义异常消息
// System.ArgumentNullException:我的自定义消息(参数"nullableValue")
nullableValue.ThrowIfNull("我的自定义消息");
// System.ArgumentOutOfRangeException:我的自定义消息(参数"dateTime")\n 实际值为 2022/3/1 10:47:15。
dateTime.Throw("我的自定义消息").IfLessThan(DateTime.Now.AddYears(20));
// System.ArgumentException:我的自定义消息(参数"isGood")
isGood.Throw("我的自定义消息").IfTrue();
// System.ArgumentException:我的自定义消息(参数"name")
name.Throw("我的自定义消息").IfEmpty();
// System.ArgumentOutOfRangeException:我的自定义消息(参数"number")\n 实际值为 5。
number.Throw("我的自定义消息").IfPositive();
3. Throw(() => new MyException())
向 Throw()
或 ThrowIfNull()
方法传递自定义异常抛出器
// MyCustomException:抛出了"MyCustomException"类型的异常。
nullableValue.ThrowIfNull(() => throw new MyCustomException());
// MyCustomException:抛出了"MyCustomException"类型的异常。
dateTime.Throw(() => throw new MyCustomException()).IfLessThan(DateTime.Now.AddYears(20));
// MyCustomException:抛出了"MyCustomException"类型的异常。
isGood.Throw(() => throw new MyCustomException()).IfTrue();
// MyCustomException:抛出了"MyCustomException"类型的异常。
name.Throw(() => throw new MyCustomException()).IfEmpty();
// MyCustomException:抛出了"MyCustomException"类型的异常。
number.Throw(() => throw new MyCustomException()).IfPositive();
4. Throw(paramName => new MyException($"参数:{paramName}")
向 Throw()
或 ThrowIfNull()
方法传递一个自定义异常抛出器,该抛出器接受参数名称作为参数
这在以下场景中很有用:
void SendEmail(User user)
{
user.Throw(paramName => new UserException(message: "由于用户详细信息无效,无法发送电子邮件。", paramName: paramName))
.IfWhiteSpace(user => user.FirstName) // UserException: 由于用户详细信息无效,无法发送电子邮件。 (参数 'user: user => user.FirstName')
.IfWhiteSpace(user => user.LastName) // UserException: 由于用户详细信息无效,无法发送电子邮件。 (参数 'user: user => user.LastName')
.IfNull(user => user.Email) // UserException: 由于用户详细信息无效,无法发送电子邮件。 (参数 'user: user => user.Email')
.IfLongerThan(user => user.Email!, 100); // UserException: 由于用户详细信息无效,无法发送电子邮件。 (参数 'user: user => user.Email!')
emailService.TrySendEmail(user)
.Throw(() => new EmailException("无法发送电子邮件。"))
.IfFalse();
}
// MyCustomException: 参数名称: nullableValue.
nullableValue.ThrowIfNull(paramName => throw new MyCustomException($"参数名称: {paramName}."));
// MyCustomException: 参数名称: dateTime.
dateTime.Throw(paramName => throw new MyCustomException($"参数名称: {paramName}.")).IfLessThan(DateTime.Now.AddYears(20));
// MyCustomException: 参数名称: isGood.
isGood.Throw(paramName => throw new MyCustomException($"参数名称: {paramName}.")).IfTrue();
// MyCustomException: 参数名称: name.
name.Throw(paramName => throw new MyCustomException($"参数名称: {paramName}.")).IfEmpty();
// MyCustomException: 参数名称: number.
number.Throw(paramName => throw new MyCustomException($"参数名称: {paramName}.")).IfPositive();
用法
常见类型
布尔值
value.Throw().IfTrue(); // ArgumentException: 值不应为true (参数 'value')
value.Throw().IfFalse(); // ArgumentException: 值应为true (参数 'value')
// 任何返回布尔值的方法都可以内联其异常抛出逻辑。
Enum.TryParse("意外值", out EmployeeType value)
.Throw()
.IfFalse(); // System.ArgumentException: 值应为true。 (参数 'Enum.TryParse("意外值", out EmployeeType value)')
可空值类型 (bool?
, int?
, double?
, DateTime?
等)
bool? value = null;
value.ThrowIfNull(); // ArgumentNullException: 值不能为null。 (参数 'value')
// 在验证 `ThrowIfNull` 后,可以使用任何常规值类型扩展。
value.ThrowIfNull() // ArgumentNullException: 值不能为null。 (参数 'value')
.IfTrue(); // ArgumentException: 值不应为true (参数 'value')
// `ThrowIfNull` 返回的值可以隐式转换为原始的非可空类型。
bool nonNullableValue = value.ThrowIfNull(); // ArgumentNullException: 值不能为null。 (参数 'value')
字符串
name.Throw().IfEmpty(); // System.ArgumentException: 字符串不应为空。 (参数 'name')
name.Throw().IfWhiteSpace(); // System.ArgumentException: 字符串不应只包含空白字符。 (参数 'name')
name.Throw().IfLengthEquals(7); // System.ArgumentException: 字符串长度不应等于7。 (参数 'name')
name.Throw().IfLengthNotEquals(10); // System.ArgumentException: 字符串长度应等于10。 (参数 'name')
name.Throw().IfShorterThan(10); // System.ArgumentException: 字符串长度不应短于10个字符。 (参数 'name')
name.Throw().IfLongerThan(3); // System.ArgumentException: 字符串长度不应超过3个字符。 (参数 'name')
name.Throw().IfEquals("Amichai"); // System.ArgumentException: 字符串不应等于 'Amichai' (比较类型: 'Ordinal')。 (参数 'name')
name.Throw().IfEquals("Amichai", StringComparison.InvariantCulture); // System.ArgumentException: 字符串不应等于 'Amichai' (比较类型: 'InvariantCulture')。 (参数 'name')
name.Throw().IfEqualsIgnoreCase("AMICHAI"); // System.ArgumentException: 字符串不应等于 'AMICHAI' (比较类型: 'OrdinalIgnoreCase')。 (参数 'name')
name.Throw().IfNotEquals("Dan"); // System.ArgumentException: 字符串应等于 'Dan' (比较类型: 'Ordinal')。 (参数 'name')
name.Throw().IfNotEquals("Dan", StringComparison.InvariantCultureIgnoreCase); // System.ArgumentException: 字符串应等于 'Dan' (比较类型: 'InvariantCultureIgnoreCase')。 (参数 'name')
name.Throw().IfNotEqualsIgnoreCase("Dan"); // System.ArgumentException: 字符串应等于 'Dan' (比较类型: 'OrdinalIgnoreCase')。 (参数 'name')
name.Throw().IfContains("substring"); // System.ArgumentException: 字符串不应包含 'substring' (比较类型: 'Ordinal')。 (参数 'name')
name.Throw().IfContains("substring", ComparisonType.InvariantCulture); // System.ArgumentException: 字符串应包含 'substring' (比较类型: 'InvariantCulture')。 (参数 'name')
name.Throw().IfNotContains("substring"); // System.ArgumentException: 字符串应包含 'substring' (比较类型: 'Ordinal')。 (参数 'name')
name.Throw().IfNotContains("substring", ComparisonType.InvariantCultureIgnoreCase); // System.ArgumentException: 字符串应包含 'substring' (比较类型: 'InvariantCultureIgnoreCase')。 (参数 'name')
name.Throw().IfStartsWith("Jer"); // System.ArgumentException: 字符串不应以 'Jer' 开头 (比较类型: 'Ordinal')。 (参数 'name')
name.Throw().IfStartsWith("JER", StringComparison.OrdinalIgnoreCase); // System.ArgumentException: 字符串不应以 'JER' 开头 (比较类型: 'OrdinalIgnoreCase')。 (参数 'name')
name.Throw().IfNotStartsWith("dan"); // System.ArgumentException: 字符串应以 'dan' 开头 (比较类型: 'Ordinal')。 (参数 'name')
name.Throw().IfNotStartsWith("dan", StringComparison.InvariantCultureIgnoreCase); // System.ArgumentException: 字符串应以 'dan' 开头 (比较类型: 'InvariantCultureIgnoreCase')。 (参数 'name')
name.Throw().IfEndsWith("emy"); // System.ArgumentException: 字符串不应以 'emy' 结尾 (比较类型: 'Ordinal')。 (参数 'name')
name.Throw().IfEndsWith("EMY", StringComparison.OrdinalIgnoreCase); // System.ArgumentException: 字符串不应以 'EMY' 结尾 (比较类型: 'OrdinalIgnoreCase')。 (参数 'name')
name.Throw().IfNotEndsWith("dan"); // System.ArgumentException: 字符串应以 'dan' 结尾 (比较类型: 'Ordinal')。 (参数 'name')
name.Throw().IfNotEndsWith("dan", StringComparison.OrdinalIgnoreCase); // System.ArgumentException: 字符串应以 'dan' 结尾 (比较类型: 'OrdinalIgnoreCase')。 (参数 'name')
name.Throw().IfMatches("J.*y"); // System.ArgumentException: 字符串不应匹配正则表达式模式 'J.*y' (参数 'name')
name.Throw().IfMatches("[a-z]{0,10}", RegexOptions.IgnoreCase); // System.ArgumentException: 字符串不应匹配正则表达式模式 '[a-z]{0,10}' (参数 'name')
name.Throw().IfNotMatches("^[0-9]+$"); // System.ArgumentException: 字符串应匹配正则表达式模式 '^[0-9]+$' (参数 'name')
name.Throw().IfNotMatches("abc ", RegexOptions.IgnorePatternWhitespace); // System.ArgumentException: 字符串应匹配正则表达式模式 '^[0-9]+$' (参数 'name')
集合 (IEnumerable
, IEnumerable<T>
, ICollection
, ICollection<T>
, IList
, 等)
重要提示:如果集合是未求值的表达式,该表达式将被求值。
collection.Throw().IfHasNullElements(); // System.ArgumentException: 集合不应包含空元素。 (参数 'collection')
collection.Throw().IfEmpty(); // System.ArgumentException: 集合不应为空。 (参数 'collection')
collection.Throw().IfNotEmpty(); // System.ArgumentException: 集合应为空。 (参数 'collection')
collection.Throw().IfCountLessThan(5); // System.ArgumentException: 集合计数不应小于5。 (参数 'collection')
collection.Throw().IfCountGreaterThan(1); // System.ArgumentException: 集合计数不应大于1。 (参数 'collection')
collection.Throw().IfCountEquals(0); // System.ArgumentException: 集合计数不应等于0。 (参数 'collection')
collection.Throw().IfCountNotEquals(0); // System.ArgumentException: 集合计数应等于0。 (参数 'collection')
collection.Throw().IfContains("value"); // System.ArgumentException: 集合不应包含元素。 (参数 'person: p => p.Friends')
collection.Throw().IfNotContains("value"); // System.ArgumentException: 集合应包含元素。 (参数 'person: p => p.Friends')
DateTime
dateTime.Throw().IfUtc(); // System.ArgumentException: 值不应为Utc。 (参数 'dateTime')
dateTime.Throw().IfNotUtc(); // System.ArgumentException: 值应为Utc。 (参数 'dateTime')
dateTime.Throw().IfDateTimeKind(DateTimeKind.Unspecified); // System.ArgumentException: 值不应为Unspecified。 (参数 'dateTime')
dateTime.Throw().IfDateTimeKindNot(DateTimeKind.Local); // System.ArgumentException: 值应为Local。 (参数 'dateTime')
dateTime.Throw().IfGreaterThan(DateTime.Now.AddYears(-20)); // System.ArgumentOutOfRangeException: 值不应大于 2002/2/28 16:41:19。 (参数 'dateTime')
dateTime.Throw().IfLessThan(DateTime.Now.AddYears(20)); // System.ArgumentOutOfRangeException: 值不应小于 2042/2/28 16:41:46。 (参数 'dateTime')
dateTime.Throw().IfEquals(other); // System.ArgumentException: 值不应等于 2022/2/28 16:44:39。 (参数 'dateTime')
枚举
employeeType.Throw().IfOutOfRange(); // System.ArgumentOutOfRangeException: 值应在枚举中定义。 (参数 'employeeType')
employeeType.Throw().IfEquals(EmployeeType.FullTime); // System.ArgumentException: 值不应等于FullTime。 (参数 'employeeType')
相等性 (非空类型)
dateTime.Throw().IfDefault(); // System.ArgumentException: 值不应为默认值。 (参数 'dateTime')
dateTime.Throw().IfNotDefault(); // System.ArgumentException: 值应为默认值。 (参数 'dateTime')
number.Throw().IfEquals(5); // System.ArgumentException: 值不应等于5。 (参数 'number')
number.Throw().IfNotEquals(3); // System.ArgumentException: 值应等于3。 (参数 'number')
Uri
uri.Throw().IfHttps(); // System.ArgumentException: Uri方案不应该是https。(参数'uri')
uri.Throw().IfNotHttps(); // System.ArgumentException: Uri方案应该是https。(参数'uri')
uri.Throw().IfHttp(); // System.ArgumentException: Uri方案不应该是http。(参数'uri')
uri.Throw().IfNotHttp(); // System.ArgumentException: Uri方案应该是http。(参数'uri')
uri.Throw().IfScheme(Uri.UriSchemeHttp); // System.ArgumentException: Uri方案不应该是http。(参数'uri')
uri.Throw().IfSchemeNot(Uri.UriSchemeFtp); // System.ArgumentException: Uri方案应该是ftp。(参数'uri')
uri.Throw().IfPort(800); // System.ArgumentException: Uri端口不应该是80。(参数'uri')
uri.Throw().IfPortNot(8080); // System.ArgumentException: Uri端口应该是8080。(参数'uri')
uri.Throw().IfAbsolute(); // System.ArgumentException: Uri应该是相对的。(参数'uri')
uri.Throw().IfRelative(); // System.ArgumentException: Uri应该是绝对的。(参数'uri')
uri.Throw().IfNotAbsolute(); // System.ArgumentException: Uri应该是绝对的。(参数'uri')
uri.Throw().IfNotRelative(); // System.ArgumentException: Uri应该是相对的。(参数'uri')
uri.Throw().IfHost("www.google.com"); // System.ArgumentException: Uri主机不应该是www.google.com。(参数'uri')
uri.Throw().IfHostNot("www.google.com"); // System.ArgumentException: Uri主机应该是www.google.com。(参数'uri')
可比较类型(int
、double
、decimal
、long
、float
、short
、DateTime
、DateOnly
、TimeOnly
等)
number.Throw().IfPositive(); // System.ArgumentOutOfRangeException: 值不应该大于0。(参数'number')\n 实际值为5。
number.Throw().IfNegative(); // System.ArgumentOutOfRangeException: 值不应该小于0。(参数'number')\n 实际值为-5。
number.Throw().IfLessThan(10); // System.ArgumentOutOfRangeException: 值不应该小于10。(参数'number')\n 实际值为5。
number.Throw().IfGreaterThan(3); // System.ArgumentOutOfRangeException: 值不应该大于3。(参数'number')\n 实际值为5。
number.Throw().IfGreaterThanOrEqualTo(5); // System.ArgumentOutOfRangeException: 值不应该大于或等于5。(参数'number')\n 实际值为6。
number.Throw().IfLessThanOrEqualTo(5); // System.ArgumentOutOfRangeException: 值不应该小于或等于5。(参数'number')\n 实际值为4。
number.Throw().IfPositiveOrZero(); // System.ArgumentOutOfRangeException: 值不应该大于或等于0。(参数'number')\n 实际值为4。
number.Throw().IfNegativeOrZero(); // System.ArgumentOutOfRangeException: 值不应该小于或等于0。(参数'number')\n 实际值为-1。
number.Throw().IfOutOfRange(0, 5); // System.ArgumentOutOfRangeException: 值应该在0和5之间。(参数'number')\n 实际值为-5。
number.Throw().IfInRange(0, 5); // System.ArgumentOutOfRangeException: 值不应该在0和5之间。(参数'number')\n 实际值为4。
类型
myObject.Throw().IfType<string>(); // System.ArgumentException: 参数不应该是'String'类型。(参数'myObject')。
myObject.Throw().IfNotType<string>(); // System.ArgumentException: 参数应该是'String'类型。(参数'myObject')。
嵌套属性
布尔属性
person.Throw().IfTrue(p => p.IsFunny); // System.ArgumentException: 值不应满足条件(条件:'person => person.IsFunny')。(参数'person')
person.Throw().IfFalse(p => p.IsFunny); // System.ArgumentException: 值应满足条件(条件:'person => person.IsFunny')。(参数'person')
// 我们可以将异常抛出逻辑内联到方法调用中。
Person person = GetPerson().Throw().IfTrue(person => person.Age < 18); // System.ArgumentException: 值不应满足条件(条件:'person => person.Age < 18')。(参数'GetPerson()')
字符串属性
person.Throw().IfEmpty(p => p.Name); // System.ArgumentException: 字符串不应为空。(参数'person: p => p.Name')
person.Throw().IfWhiteSpace(p => p.Name); // System.ArgumentException: 字符串不应仅包含空白字符。(参数'person: p => p.Name')
person.Throw().IfNullOrWhiteSpace(p => p.Name); // System.ArgumentException: 字符串不应为null或仅包含空白字符。(参数'person: p => p.Name')
person.Throw().IfNullOrEmpty(p => p.Name); // System.ArgumentException: 字符串不应为null或空。(参数'person: p => p.Name')
person.Throw().IfLengthEquals(p => p.Name, 7); // System.ArgumentException: 字符串长度不应等于7。(参数'person: p => p.Name')
person.Throw().IfLengthNotEquals(p => p.Name, 10); // System.ArgumentException: 字符串长度应等于10。(参数'person: p => p.Name')
person.Throw().IfShorterThan(p => p.Name, 10); // System.ArgumentException: 字符串不应短于10个字符。(参数'person: p => p.Name')
person.Throw().IfLongerThan(p => p.Name, 3); // System.ArgumentException: 字符串不应长于3个字符。(参数'person: p => p.Name')
person.Throw().IfEquals(p => p.Name, "Amichai"); // System.ArgumentException: 字符串不应等于'Amichai'(比较类型:'Ordinal')。(参数'person: p => p.Name')
person.Throw().IfEquals(p => p.Name, "Amichai", StringComparison.InvariantCulture); // System.ArgumentException: 字符串不应等于'Amichai'(比较类型:'InvariantCulture')。(参数'person: p => p.Name')
person.Throw().IfEqualsIgnoreCase(p => p.Name, "AMICHAI"); // System.ArgumentException: 字符串不应等于'AMICHAI'(比较类型:'OrdinalIgnoreCase')。(参数'person: p => p.Name')
person.Throw().IfNotEquals(p => p.Name, "Dan"); // System.ArgumentException: 字符串应等于'Dan'(比较类型:'Ordinal')。(参数'person: p => p.Name')
person.Throw().IfNotEquals(p => p.Name, "Dan", StringComparison.InvariantCultureIgnoreCase); // System.ArgumentException: 字符串应等于'Dan'(比较类型:'InvariantCultureIgnoreCase')。(参数'person: p => p.Name')
person.Throw().IfNotEqualsIgnoreCase(p => p.Name, "Dan"); // System.ArgumentException: 字符串应等于'Dan'(比较类型:'OrdinalIgnoreCase')。(参数'person: p => p.Name')
person.Throw().IfContains(p => p.Name, "substring"); // System.ArgumentException: 字符串不应包含'substring'(比较类型:'Ordinal')。(参数'person: p => p.Name')
person.Throw().IfContains(p => p.Name, "substring", ComparisonType.InvariantCulture); // System.ArgumentException: 字符串应包含'substring'(比较类型:'InvariantCulture')。(参数'person: p => p.Name')
person.Throw().IfNotContains(p => p.Name, "substring"); // System.ArgumentException: 字符串应包含'substring'(比较类型:'Ordinal')。(参数'person: p => p.Name')
person.Throw().IfNotContains(p => p.Name, "substring", ComparisonType.InvariantCultureIgnoreCase); // System.ArgumentException: 字符串应包含'substring'(比较类型:'InvariantCultureIgnoreCase')。(参数'person: p => p.Name')
person.Throw().IfStartsWith(p => p.Name, "Jer"); // System.ArgumentException: 字符串不应以'Jer'开头(比较类型:'Ordinal')。(参数'person: p => p.Name')
person.Throw().IfStartsWith(p => p.Name, "JER", StringComparison.OrdinalIgnoreCase); // System.ArgumentException: 字符串不应以'JER'开头(比较类型:'OrdinalIgnoreCase')。(参数'person: p => p.Name')
person.Throw().IfNotStartsWith(p => p.Name, "dan"); // System.ArgumentException: 字符串应以'dan'开头(比较类型:'Ordinal')。(参数'person: p => p.Name')
person.Throw().IfNotStartsWith(p => p.Name, "dan", StringComparison.InvariantCultureIgnoreCase); // System.ArgumentException: 字符串应以'dan'开头(比较类型:'InvariantCultureIgnoreCase')。(参数'person: p => p.Name')
person.Throw().IfEndsWith(p => p.Name, "emy"); // System.ArgumentException: 字符串不应以'emy'结尾(比较类型:'Ordinal')。(参数'person: p => p.Name')
person.Throw().IfEndsWith(p => p.Name, "EMY", StringComparison.OrdinalIgnoreCase); // System.ArgumentException: 字符串不应以'EMY'结尾(比较类型:'OrdinalIgnoreCase')。(参数'person: p => p.Name')
person.Throw().IfNotEndsWith(p => p.Name, "dan"); // System.ArgumentException: 字符串应以'dan'结尾(比较类型:'Ordinal')。(参数'person: p => p.Name')
person.Throw().IfNotEndsWith(p => p.Name, "dan", StringComparison.OrdinalIgnoreCase); // System.ArgumentException: 字符串应以'dan'结尾(比较类型:'OrdinalIgnoreCase')。(参数'person: p => p.Name')
person.Throw().IfMatches(p => p.Name, "J.*y"); // System.ArgumentException: 字符串不应匹配正则表达式模式'J.*y'(参数'person: p => p.Name')
person.Throw().IfMatches(p => p.Name, "[a-z]{0,10}", RegexOptions.IgnoreCase); // System.ArgumentException: 字符串不应匹配正则表达式模式'[a-z]{0,10}'(参数'person: p => p.Name')
person.Throw().IfNotMatches(p => p.Name, "^[0-9]+$"); // System.ArgumentException: 字符串应匹配正则表达式模式'^[0-9]+$'(参数'person: p => p.Name')
person.Throw().IfNotMatches(p => p.Name, "abc ", RegexOptions.IgnorePatternWhitespace); // System.ArgumentException: 字符串应匹配正则表达式模式'^[0-9]+$'(参数'person: p => p.Name')
集合属性
person.Throw().IfHasNullElements(p => p.Friends); // System.ArgumentException: 集合不应包含null元素。(参数'person: p => p.Friends')
person.Throw().IfEmpty(p => p.Friends); // System.ArgumentException: 集合不应为空。(参数'person: p => p.Friends')
person.Throw().IfNotEmpty(p => p.Friends); // System.ArgumentException: 集合应为空。(参数'person: p => p.Friends')
person.Throw().IfCountLessThan(p => p.Friends, 5); // System.ArgumentException: 集合数量不应少于5。(参数'person: p => p.Friends')
person.Throw().IfCountGreaterThan(p => p.Friends, 1); // System.ArgumentException: 集合数量不应大于1。(参数'person: p => p.Friends')
person.Throw().IfCountEquals(p => p.Friends, 0); // System.ArgumentException: 集合数量不应等于0。(参数'person: p => p.Friends')
person.Throw().IfCountNotEquals(p => p.Friends, 0); // System.ArgumentException: 集合数量应等于0。(参数'person: p => p.Friends')
person.Throw().IfContains(p => p.Friends, "Amichai"); // System.ArgumentException: 集合不应包含元素。(参数'person: p => p.Friends')
person.Throw().IfNotContains(p => p.Friends, "Amichai"); // System.ArgumentException: 集合应包含元素。(参数'person: p => p.Friends')
DateTime属性
person.Throw().IfUtc(p => p.DateOfBirth); // System.ArgumentException: 值不应为Utc。 (参数 'person: p => p.DateOfBirth')
person.Throw().IfNotUtc(p => p.DateOfBirth); // System.ArgumentException: 值应为Utc。 (参数 'person: p => p.DateOfBirth')
person.Throw().IfDateTimeKind(p => p.DateOfBirth, DateTimeKind.Unspecified); // System.ArgumentException: 值不应为Unspecified。 (参数 'person: p => p.DateOfBirth')
person.Throw().IfDateTimeKindNot(p => p.DateOfBirth, DateTimeKind.Local); // System.ArgumentException: 值应为Local。 (参数 'person: p => p.DateOfBirth')
person.Throw().IfGreaterThan(p => p.DateOfBirth, DateTime.Now.AddYears(-20)); // System.ArgumentOutOfRangeException: 值不应大于 2/28/2002 4:41:19 PM。 (参数 'person: p => p.DateOfBirth')
person.Throw().IfLessThan(p => p.DateOfBirth, DateTime.Now.AddYears(20)); // System.ArgumentOutOfRangeException: 值不应小于 2/28/2042 4:41:46 PM。 (参数 'person: p => p.DateOfBirth')
person.Throw().IfEquals(p => p.DateOfBirth, other); // System.ArgumentException: 值不应等于 2/28/2022 4:45:12 PM。 (参数 'person: p => p.DateOfBirth')
枚举属性
person.Throw().IfOutOfRange(p => p.EmployeeType); // System.ArgumentOutOfRangeException: 值应在枚举中定义。 (参数 'person: p => p.EmployeeType')
person.Throw().IfEquals(p => p.EmployeeType, EmployeeType.FullTime); // System.ArgumentException: 值不应等于FullTime。 (参数 'person: p => p.EmployeeType')
属性相等性
person.Throw().IfDefault(p => p.DateOfBirth); // System.ArgumentException: 值不应为默认值。 (参数 'person: p => p.DateOfBirth')
person.Throw().IfNotDefault(p => p.DateOfBirth); // System.ArgumentException: 值应为默认值。 (参数 'person: p => p.DateOfBirth')
person.Throw().IfNull(p => p.MiddleName); // System.ArgumentNullException: 值不能为null。 (参数 'person: p => p.MiddleName')
person.Throw().IfNotNull(p => p.MiddleName); // System.ArgumentException: 值应为null。 (参数 'person: p => p.MiddleName')
person.Throw().IfEquals(p => p.Age, 5); // System.ArgumentException: 值不应等于5。 (参数 'person: p => p.Age')
person.Throw().IfNotEquals(p => p.Age, 3); // System.ArgumentException: 值应等于3。 (参数 'person: p => p.Age')
Uri属性
person.Throw().IfHttps(p => p.Website); // System.ArgumentException: Uri协议不应为https。 (参数 'person: p => p.Website')
person.Throw().IfNotHttps(p => p.Website); // System.ArgumentException: Uri协议应为https。 (参数 'person: p => p.Website')
person.Throw().IfHttp(p => p.Website); // System.ArgumentException: Uri协议不应为http。 (参数 'person: p => p.Website')
person.Throw().IfNotHttp(p => p.Website); // System.ArgumentException: Uri协议应为http。 (参数 'person: p => p.Website')
person.Throw().IfScheme(p => p.Website, Uri.UriSchemeHttp); // System.ArgumentException: Uri协议不应为http。 (参数 'person: p => p.Website')
person.Throw().IfSchemeNot(p => p.Website, Uri.UriSchemeFtp); // System.ArgumentException: Uri协议应为ftp。 (参数 'person: p => p.Website')
person.Throw().IfPort(p => p.Website, 800); // System.ArgumentException: Uri端口不应为80。 (参数 'person: p => p.Website')
person.Throw().IfPortNot(p => p.Website, 8080); // System.ArgumentException: Uri端口应为8080。 (参数 'person: p => p.Website')
person.Throw().IfAbsolute(p => p.Website); // System.ArgumentException: Uri应为相对路径。 (参数 'person: p => p.Website')
person.Throw().IfRelative(p => p.Website); // System.ArgumentException: Uri应为绝对路径。 (参数 'person: p => p.Website')
person.Throw().IfNotAbsolute(p => p.Website); // System.ArgumentException: Uri应为绝对路径。 (参数 'person: p => p.Website')
person.Throw().IfNotRelative(p => p.Website); // System.ArgumentException: Uri应为相对路径。 (参数 'person: p => p.Website')
person.Throw().IfHost(p => p.Website, "www.google.com"); // System.ArgumentException: Uri主机不应为www.google.com。 (参数 'person: p => p.Website')
person.Throw().IfHostNot(p => p.Website, "www.google.com"); // System.ArgumentException: Uri主机应为www.google.com。 (参数 'person: p => p.Website')
可比较属性
person.Throw().IfPositive(p => p.Age); // System.ArgumentOutOfRangeException: 值不应大于0。 (参数 'person: p => p.Age')\n 实际值为5。
person.Throw().IfNegative(p => p.Age); // System.ArgumentOutOfRangeException: 值不应小于0。 (参数 'person: p => p.Age')\n 实际值为-5。
person.Throw().IfLessThan(p => p.Age, 10); // System.ArgumentOutOfRangeException: 值不应小于10。 (参数 'person: p => p.Age')\n 实际值为5。
person.Throw().IfGreaterThan(p => p.Age, 3); // System.ArgumentOutOfRangeException: 值不应大于3。 (参数 'person: p => p.Age')\n 实际值为5。
person.Throw().IfGreaterThanOrEqualTo(p => p.Age, 5); // System.ArgumentOutOfRangeException: 值不应大于或等于5。 (参数 'person: p => p.Age')\n 实际值为6。
person.Throw().IfLessThanOrEqualTo(p => p.Age, 5); // System.ArgumentOutOfRangeException: 值不应小于或等于5。 (参数 'person: p => p.Age')\n 实际值为4。
person.Throw().IfPositiveOrZero(p => p.Age); // System.ArgumentOutOfRangeException: 值不应大于或等于0。 (参数 'person: p => p.Age')\n 实际值为4。
person.Throw().IfNegativeOrZero(p => p.Age); // System.ArgumentOutOfRangeException: 值不应小于或等于0。 (参数 'person: p => p.Age')\n 实际值为-1。
person.Throw().IfOutOfRange(p => p.Age, 0, 5); // System.ArgumentOutOfRangeException: 值应在0和5之间。 (参数 'person: p => p.Age')\n 实际值为-5。
person.Throw().IfInRange(p => p.Age, 0, 5); // System.ArgumentOutOfRangeException: 值不应在0和5之间。 (参数 'person: p => p.Age')\n 实际值为4。
可扩展性
你可以通过添加自己的规则轻松扩展该库。
这里有一个简单的例子:
"foo".Throw().IfFoo(); // System.ArgumentException: 字符串不应等于'foo' (参数 '"foo"')
namespace Throw
{
public static class ValidatableExtensions
{
public static ref readonly Validatable<string> IfFoo(this in Validatable<string> validatable)
{
if (string.Equals(validatable.Value, "foo", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("字符串不应等于'foo'", validatable.ParamName);
}
return ref validatable;
}
}
}
另一个例子:
user.Throw().IfUsesFacebookOnChrome();
namespace Throw
{
public static class ValidatableExtensions
{
public static ref readonly Validatable<User> IfUsesFacebookOnChrome(this in Validatable<User> validatable)
{
if (validatable.Value.FavoriteBrowser == Browser.Chrome && validatable.Value.FavoriteWebsite == new Uri("https://facebook.com"))
{
throw new UserException("用户不应在Chrome上使用Facebook!");
}
return ref validatable;
}
}
}
如果你想在扩展中使用异常自定义,你可以使用ExceptionThrower
类,它知道如何根据自定义创建适当的异常。例如:
namespace Throw
{
public static class ValidatableExtensions
{
public static ref readonly Validatable<User> IfUsesFacebookOnChrome(this in Validatable<User> validatable)
{
if (validatable.Value.FavoriteBrowser == Browser.Chrome && validatable.Value.FavoriteWebsite == new Uri("https://facebook.com"))
{
ExceptionThrower.Throw(validatable.ParamName, validatable.ExceptionCustomizations, "用户不应在Chrome上使用Facebook。");
}
return ref validatable;
}
}
}
这将表现如下:
user.Throw()
.IfUsesFacebookOnChrome(); // System.ArgumentException: 用户不应在Chrome上使用Facebook。 (参数 'user')
user.Throw("一条不同的消息。")
.IfUsesFacebookOnChrome(); // System.ArgumentException: 一条不同的消息。 (参数 'user')
user.Throw(() => new Exception("一个不同的异常。"))
.IfUsesFacebookOnChrome(); // System.Exception: 一个不同的异常。
user.Throw(paramName => new Exception($"一个不同的异常。参数名: '{paramName}'"))
.IfUsesFacebookOnChrome(); // System.Exception: 一个不同的异常。参数名: 'user'
条件编译
有一个你想从发布版本中排除的Throw()
规则吗?
只需在规则中添加OnlyInDebug()
,它就会从非调试版本中排除。
"foo".Throw().IfEquals("foo").OnlyInDebug();
dotnet run -c Debug # 将抛出异常
dotnet run -c Release # 不会抛出异常
即将推出的功能
- 更多扩展方法: 更多规则即将推出! 欢迎贡献!
贡献
欢迎提出任何想法、错误或功能请求的问题。
我们正在努力成为最快的验证库,所以如果你有改进运行时速度的建议,请与我们分享。
致谢
- Dawn.Guard - 一个出色的、快速的、直观的C#防护条款库。对这个库是一个很大的启发。
许可证
本项目根据MIT许可证条款授权。