Project Icon

throw

为.NET 6+提供流畅易用的异常处理

Throw是一个为.NET 6+设计的异常处理库,具有简洁、流畅和可扩展的特点。该库支持多种数据类型验证,包括字符串、集合和日期时间等。开发者可自定义异常消息和类型,实现灵活的异常处理。Throw库通过提供易用的API,有助于提高代码健壮性和可读性,成为.NET开发中进行参数验证的有力工具。

drawing

NuGet

构建 发布 Throw 到 NuGet codecov

GitHub 贡献者 GitHub 星标 GitHub 许可证


一个简单、流畅、可扩展且完全可定制的用于在 .NET 6+ 中抛出异常的库

dotnet add package throw

入门 png


给它一个星标 ⭐!

喜欢它吗?通过给这个项目一个星标来表示你的支持!

可空类型与非空类型

这个库设计时考虑了启用可空引用类型特性的情况。

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')

可比较类型(intdoubledecimallongfloatshortDateTimeDateOnlyTimeOnly等)

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许可证条款授权。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号