C# CuttingEdge.Conditions 验证帮助类库 文档翻译
2021-03-28 08:24
标签:使用 重载 dep eva add 告诉 eof san count 项目主页: https://archive.codeplex.com/?p=conditions 作者博客关于项目的文档(翻译原文): https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=38#Designed_Behavior CuttingEdge.Conditions 可帮助开发人员在其.NET 3.5代码库中编写前后条件验证。 编写这些验证很容易,它提高了代码的可读性和可维护性。 警告: 此帖子基于CuttingEdge.Conditions 的 预览版本发布。虽然库的大多数概念和行为都是相同的,但最终版本有一些更改。 其中最明显的是删除了 Requires() 和 Ensures{} 方法的扩展方法行为。 请注意,不再支持以下语法:c.Requires().IsNotNull() ,建议的语法是 Condition.Requires(c).IsNotNull()。 请在阅读本文时牢记这一点。 编写前置条件验证可以提高代码质量。具有验证的代码更易于理解,并允许开发人员更快地发现错误,主要是在开发期间发现这些问题而不是在调试期间。 然而,编写前置条件验证一直是编程中不太好处理的地方。编写它需要时间,我和许多开发人员(甚至是我尊重的人)都会跳过编写它们。 跳过前置条件验证将导致代码更难以使用并且可能被滥用。它允许开发人员传递一些无效的方法参数, 这会导致意外的程序行为以及来自调用堆栈内部的那些可怕的 NullReferenceException 等异常。它会导致更多的错误,从而花费更多的时间进行调试。 CuttingEdge.Conditions 库试图降低编写前置条件验证的障碍并使代码更具可读性,从而产生更好的代码,更少的错误和更短的开发周期。 要了解 CuttingEdge.Conditions 如何尝试实现这一目标,让我们首先看看我们可能每天编写的一些代码。 这是一个前置条件验证的例子,旧的实现方式: 对于这样一些简单的验证,这是一些非常多的代码! 以下是 CuttingEdge.Conditions 的实现方式: 这是完全不同的,不是吗? 它不仅代码少得多; 它也非常易读。请注意,两种方法都有完全相同的合同; 两种方法抛出完全相同的异常! 除了这些正常的前提条件检查,CuttingEdge.Conditions还允许您进行后置条件检查。 与先决条件不同,违反后置条件纯粹是内部原因。 它可以被认为是一个错误。在这种情况下抛出ArgumentException会明显混淆使用该代码的开发人员。由于存在这种差异,CuttingEdge.Conditions 对违反后置条件的代码总会抛出一个 PostconditionException 。 以下是后置条件检查的示例: 后置条件示例显示了两个有趣的事情。 首先,使用Ensures扩展方法来启动后置条件验证。 其次,方法调用可以以流畅的方式链接,如 IsNotNull 和 IsOfType 方法所示。 CuttingEdge.Conditions API有许多验证方法, 可以轻松满足98%的验证需求。目前有51种不同检查的88种扩展方法。API可分为七组: 下面我将列出 CuttingEdge.Conditions 当前beta 1版本中的所有方法。 方法的数量可能会随着时间的推移而增长,如果您认为缺少验证,请在此处或在Codeplex上发表评论。我会考虑将它们添加到库中。 另请注意,只需将扩展方法放在您自己的项目中,您就可以使用自己的方法扩展API。 Entry point methods 入口点方法 入口点方法用于启动验证。可以在每个类型的每个变量上调用这些扩展方法。目前有两种方法: Requires (2 重载) Ensures (3 重载) Requires 可以用来写先决条件,它在验证失败时抛出 ArgumentException 或 它的一个子类。 Ensures 可以用来写后置条件。它将抛出 PostconditionException。 空检查方法 如果参数需要值或不需要值,则可以使用空检查。可以对引用类型和 Nullable 有两种方法: IsNotNull(2 重载) IsNull(2 重载) 键入检查方法 有两种方法可用于类型检查: IsOfType IsNotOfType 比较检查 比较检查验证参数是否等于某个其他值或在给定范围内。 它们可以在Nullable IsEqualTo(3 重载) IsNotEqualTo(3 重载) IsGreaterThan(3 重载) IsNotGreaterThan(3 重载) IsGreaterOrEqual(3 重载) IsNotGreaterOrEqual(3 重载) IsInRange(3 重载) IsNotInRange(3 重载) IsLessThan(3 重载) IsNotLessThan(3 重载) IsLessOrEqual(3 重载) IsNotLessOrEqual(3 重载) 集合检查 集合检查可用于(至少)实现 IEnumerable 的类型。目前有18种方法: Contains(2 重载) DoesNotContain(2 重载) ContainsAll(2 重载) DoesNotContainAll(2 重载) ContainsAny(2 重载) DoesNotContainAny(2 重载) IsEmpty IsNotEmpty HasLength DoesNotHaveLength IsLongerThan IsNotLongerThan IsLongerOrEqual IsNotLongerOrEqual IsShorterThan IsNotShorterThan IsShorterOrEqual IsNotShorterOrEqual 字符串检查 有一组单独的方法可以验证字符串,目前有16种方法: Contains DoesNotContain StartsWith(2 重载) DoesNotStartWith(2 重载) EndsWith(2 重载) DoesNotEndWith(2 重载) HasLength DoesNotHaveLength IsEmpty IsNotEmpty IsNullOrEmpty IsNotNullOrEmpty IsLongerThan IsLongerOrEqual IsShorterThan IsShorterOrEqual 自定义验证 对于使用上述方法无法完成的所有检查,使用 Evaluate 方法重载是一种解决方案。 第一个重载检查并返回一个布尔值,将在它等于false时抛出异常。 第二个重载运行一个返回布尔值的指定 Expression。这允许开发人员定义lambda表达式。这两个重载允许字面表达您想要的任何前置或后置条件。有一种方法: Evaluate(2次重载) 以下是使用Evaluate的两个示例: 这两个例子看起来很多,但它们实际上是完全不同的。 第一个示例使用布尔参数,检查速度非常快。但是,它在失败时缺少一个好的异常消息。 与 lambda 表达式的重载恰恰相反。 它必须在每次调用时编译给定的表达式,因此不应该在代码的性能敏感部分中使用它。但是在使用时,能够抛出一个具有描述性的异常消息: ‘(str.StartsWith("hello") || str.EndsWith("world"))‘ should hold for s. The actual value is ‘world hello‘. Parameter name: s。 CuttingEdge.Conditions API经过精心设计, 我希望它以最直观的方式运行(您可以在这里阅读更多关于设计过程和一些背景知识)。 下面是我做出的一些设计决策以及开发人员必须编写的代码的后果。如果这种行为很奇怪并且需要改变,请告诉我。 空值被认为小于任何非空值。 这与在.NET框架中验证对象的方式一致。以下代码行显示此行为: 包含空引用的集合参数被视为包含零元素。 对于用户来说,这种行为可能看起来很奇怪。当检查空引用时,库的用户可能希望 API 抛出 ArgumentNullException 。 但是在某些情况下,抛出异常将不是预期的行为,因此会导致API不一致。除此之外,选择空引用将会始终失败,将限制该 API 的有用性。 在某些情况下,用户可能会发现空引用是有效值。即,用户可以如下定义前提条件:“ 集合应该具有少于五个元素并且可以是空引用”。 他无法使用集合方法的 API 来表达这个前提条件。他将被迫使用 Evaluate 机制,该机制显然不太可读,并且不会抛出描述性的异常消息。 以下示例显示了设计的行为: 当空引用不是有效值时,开发人员可以使用 IsNotNull()方法。即使空引用是无效状态,也不需要这样做。以下示例显示了一些示例: 当该值列表不包含任何元素时,被检查的集合被视为包含所有指定的值。 当指定的值列表为空时,对ContainsAll方法的调用将始终成功。 以下示例显示了此行为: 当该集合不包含任何元素时,被检查的集合被认为不包含任何指定的值。 当指定的值列表为空时,对ContainsAny的调用将始终失败。 以下示例显示了此行为: 空字符串被认为具有0个字符的长度。 这里的理由与前面集合的描述大致相同。 以下示例显示了此行为: 空字符串和空字符串不被视为相等,并且有多种方法需要检查。 以下示例显示了此行为: 一个 null 字符串 仅仅会包含 null 字符串 。这种情况适合使用 StartsWith,EndsWith 和 Contains 等方法。 这就是.NET 的 String 方法的工作原理。以不同方式实现它不仅非常困难,而且用户不会期望这种行为。 以下示例显示了此行为: 检查空引用是否属于某种类型将始终成功。 这对于反向操作也是有效的。 警告: 设计的行为已更改。与下面的文本描述的相反,在最终版本中,使用null参数调用IsOfType将始终失败,并且使用null参数调用IsNotOfType现在将始终成功。 下面的代码是违反直觉的,最终的 API 模仿了C# ‘is‘ 运算符的行为。 在这里,我们看到了与之前看到的集合和字符串相同的问题。用户可以确定空引用有效。 如果没有,他将不得不在他的代码中添加一个IsNotNull检查。以下示例显示了此行为: 在具体翻之前觉得验证似乎是一件很简单的事情,但是这篇文档最后这几条体现出了这一方面的水深。 该文档与现在的 API 差距还是有一些的。而且该类库也无人维护了。原本我是打算用这个类库,或者是参考一下实现做些改进。 现在我觉得,我还是看看其他的类库吧。如果有时间的话就自己去实现一套。(估计没有的啦~ C# CuttingEdge.Conditions 验证帮助类库 文档翻译 标签:使用 重载 dep eva add 告诉 eof san count 原文地址:https://www.cnblogs.com/Aaxuan/p/9298118.html前言
1 void TheOldFashionWay(int id, IEnumerableint> col,
2 DayOfWeek day)
3 {
4 if (id 1)
5 {
6 throw new ArgumentOutOfRangeException("id",
7 String.Format("id should be greater " +
8 "than 0. The actual value is {0}.", id));
9 }
10
11 if (col == null)
12 {
13 throw new ArgumentNullException("col",
14 "collection should not be empty");
15 }
16
17 if (col.Count() == 0)
18 {
19 throw new ArgumentException(
20 "collection should not be empty", "col");
21 }
22
23 if (day >= DayOfWeek.Monday &&
24 day DayOfWeek.Friday)
25 {
26 throw new InvalidEnumArgumentException(
27 String.Format("day should be between " +
28 "Monday and Friday. The actual value " +
29 "is {0}.", day));
30 }
31
32 // Do method work
33 }
1 //旧的调用方式
2 void TheConditionsWay(int id, IEnumerableint> col,
3 DayOfWeek day)
4 {
5 id.Requires("id").IsGreaterThan(0);
6 col.Requires("col").IsNotEmpty();
7 day.Requires("day").IsInRange(DayOfWeek.Monday, DayOfWeek.Friday);
8
9 // Do method work
10 }
11
12 //新的调用方式
13 private static void Main(string[] args)
14 {
15 var id = 0;
16
17 Condition.Requires(id)
18 .IsGreaterThan(20)
19 .IsInRange(1, 999) // ArgumentOutOfRangeException on failure
20 .IsNotEqualTo(1000,"编号不能为 1000"); // throws ArgumentException on failure
21
22 var text = "hahahahhaha";
23
24 Condition.Requires(text, "字符串")
25
26 .StartsWith("h") // throws ArgumentException on failure
27 .EndsWith("a") // throws ArgumentException on failure
28 .Evaluate(text.Contains("abc") || text.Contains("cba")); // arg ex
29 }
1 void TheConditionsWay(int id, IEnumerableint> col,
2 DayOfWeek day)
3 {
4 id.Requires("id").IsGreaterThan(0);
5 col.Requires("col").IsNotEmpty();
6 day.Requires("day").IsInRange(DayOfWeek.Monday, DayOfWeek.Friday);
7
8 // Do method work
9 }
API
1 // Evaluate with boolean
2 s.Requires("s").Evaluate(
3 s.StartsWith("hello") || s.EndsWith("world"));
4 // Evaluate using a lambda expression
5 s.Requires("s").Evaluate((str) =>
6 str.StartsWith("hello") || str.EndsWith("world"));
1 int? i = null;
2 // Next check will pass, because null is
3 // smaller than Int32.MinValue.
4 i.Requires().IsLessThan(Int32.MinValue);
1 IEnumerable c = null;
2 // Both HasLength and IsEmpty checks will
3 // pass, because c equals null.
4 c.Requires().HasLength(0);
5 c.Requires().IsEmpty();
6 // IsShorterThan will pass, because c is
7 // clearly shorter than 5 characters.
8 c.Requires().IsShorterThan(5);
9 // When c equals null, it doesn‘t contain
10 // any elements, so we‘d expect
11 // the next lines to pass.
12 c.Requires().DoesNotContain("value");
13 c.Requires().DoesNotContainAny(new string[] { "a", "b" });
1 // Use IsNotNull() to check for null.
2 c.Requires().IsNotNull().IsShorterThan(5);
3 // IsNotEmpty() will throw an ArgumentNullException
4 // when c equals null and an ArgumentException
5 // when c is empty but not null.
6 c.Requires().IsNotEmpty();
1 Collectionint> c =
2 new Collectionint> { 1, 2, 3, 4, 5 };
3 // All checks will pass.
4 c.Requires().ContainsAll(new int[] { 1, 2 });
5 c.Requires().ContainsAll(new int[] { 1 });
6 c.Requires().ContainsAll(new int[0] { });
7 c.Requires().ContainsAll(null);
1 Collectionint> c = new Collectionint> { 1, 2, 3, 4, 5 };
2 // Next two checks will pass.
3 c.Requires().ContainsAny(new int[] { 1, 9 });
4 c.Requires().ContainsAny(new int[] { 1 });
5 // Next two checks will fail, because the
6 // specified lists are empty.
7 c.Requires().ContainsAny(new int[0] { });
8 c.Requires().ContainsAny(null);
1 string s = null;
2 // Next check passes.
3 s.Requires().HasLength(0);
4 s.Requires().IsShorterThan(5);
5 s.Requires().IsLongerThan(-1);
6 // You should use IsEmpty() or IsNotNull()
7 // if null is not a valid value.
8 s.Requires().IsEmpty();
9 s.Requires().IsNotNull().HasLength(0);
1 string s = null;
2 // The following checks will fail.
3 s.Requires().IsEqualTo(String.Empty);
4 s.Requires().IsEmpty();
5 // The following checks will pass.
6 s.Requires().IsNullOrEmpty();
7 s.Requires().IsNull();
1 string s = null;
2 // All checks below will fail.
3 s.Requires().Contains(String.Empty);
4 String.Empty.Requires().Contains(null);
5 String.Empty.Requires().EndsWith(null);
1 object o = null;
2 // Both checks below will pass, because o equals null.
3 o.Requires().IsOfType(typeof(string));
4 o.Requires().IsNotOfType(typeof(object));
5 // Use IsNotNull() when null is not a valid value.
6 o.Requires().IsNotNull().IsOfType(typeof(string));
7 o.Requires().IsNotNull().IsNotOfType(typeof(object));
上一篇:flume与hdfs
下一篇:C#后台对密码框不能直接复制
文章标题:C# CuttingEdge.Conditions 验证帮助类库 文档翻译
文章链接:http://soscw.com/index.php/essay/68955.html