任何语言中的一个常见问题是断言发送到方法的参数满足您的要求,如果不满足,则发送好的,信息丰富的错误消息.这种代码反复重复,我们经常尝试为它创建帮助器.然而,在C#中,似乎那些帮助者被迫处理语言和编译器强加给我们的一些重复.为了表明我的意思,让我提供一些没有帮助的原始代码,然后是一个可能的帮助器.然后,我会指出帮助器中的重复并准确地说出我的问题.
首先,代码没有任何帮助:
public void SomeMethod(string firstName, string lastName, int age)
{
if(firstName == null)
{
throw new WhateverException("The value for firstName cannot be null.");
}
if(lastName == null)
{
throw new WhateverException("The value for lastName cannot be null.");
}
// Same kind of code for age, making sure it is a reasonable range (< 150, for example).
// You get the idea
}
Run Code Online (Sandbox Code Playgroud)
}
现在,代码合理地尝试帮助:
public void SomeMethod(string firstName, string lastName, int age)
{
Helper.Validate( x=> x !=null, "firstName", firstName);
Helper.Validate( x=> x!= null, "lastName", lastName);
}
Run Code Online (Sandbox Code Playgroud)
主要的问题是这样的:请注意代码如何具有传递参数的值和参数("名字"的名称和的firstName).这是错误消息可以说,"Blah blah blah firstName参数的值." 你有没有办法用反射或其他任何东西解决这个问题?还是一种减轻痛苦的方法?
更一般地说,您是否找到了其他方法来简化验证参数的任务,同时减少代码重复?
编辑:我读过人们谈论使用Parameters属性,但从来没有找到解决方法.谁有运气呢?
谢谢!
Joh*_*lla 15
你应该查看代码合同 ; 他们几乎完全按照你的要求行事.例:
[Pure]
public static double GetDistance(Point p1, Point p2)
{
CodeContract.RequiresAlways(p1 != null);
CodeContract.RequiresAlways(p2 != null);
// ...
}
Run Code Online (Sandbox Code Playgroud)
Cha*_*ers 11
哇,我在这里找到了一些非常有趣的东西.Chris上面给出了另一个Stack Overflow问题的链接.其中一个答案指向一篇博文,其中描述了如何获取这样的代码:
public static void Copy<T>(T[] dst, long dstOffset, T[] src, long srcOffset, long length)
{
Validate.Begin()
.IsNotNull(dst, “dst”)
.IsNotNull(src, “src”)
.Check()
.IsPositive(length)
.IsIndexInRange(dst, dstOffset, “dstOffset”)
.IsIndexInRange(dst, dstOffset + length, “dstOffset + length”)
.IsIndexInRange(src, srcOffset, “srcOffset”)
.IsIndexInRange(src, srcOffset + length, “srcOffset + length”)
.Check();
for (int di = dstOffset; di < dstOffset + length; ++di)
dst[di] = src[di - dstOffset + srcOffset];
}
Run Code Online (Sandbox Code Playgroud)
我不相信这是在最好的答案,但可以肯定的是有趣的.这是来自Rick Brewster 的博客文章.
几周前我解决了这个确切的问题,因为我认为测试库似乎需要一百万个不同的版本Assert才能使他们的消息具有描述性,这很奇怪.
简要总结 - 给出这段代码:
int x = 3;
string t = "hi";
Assert(() => 5*x + (2 / t.Length) < 99);
Run Code Online (Sandbox Code Playgroud)
我的Assert函数可以打印出传递给它的内容的以下摘要:
(((5 * x) + (2 / t.Length)) < 99) == True where
{
((5 * x) + (2 / t.Length)) == 16 where
{
(5 * x) == 15 where
{
x == 3
}
(2 / t.Length) == 1 where
{
t.Length == 2 where
{
t == "hi"
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
因此,所有标识符名称和值以及表达式的结构都可以包含在异常消息中,而无需在引用的字符串中重述它们.
好吧,伙计们,这又是我,我找到了令人惊讶和令人愉快的其他东西.这是另一个博客文章,上面提到的克里斯提到的其他SO问题.
这个人的方法让你写这个:
public class WebServer
{
public void BootstrapServer( int port, string rootDirectory, string serverName )
{
Guard.IsNotNull( () => rootDirectory );
Guard.IsNotNull( () => serverName );
// Bootstrap the server
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,没有包含"rootDirectory"的字符串,也没有包含"serverName"的字符串!! 然而他的错误消息可以说"rootDirectory参数不能为空".
这正是我想要的,超出了我的期望.这是该家伙博客文章的链接.
实现非常简单,如下所示:
public static class Guard
{
public static void IsNotNull<T>(Expression<Func<T>> expr)
{
// expression value != default of T
if (!expr.Compile()().Equals(default(T)))
return;
var param = (MemberExpression) expr.Body;
throw new ArgumentNullException(param.Member.Name);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,这会使用"静态反射",因此在紧密循环或其他情况下,您可能希望使用上面的Rick Brewster方法.
我发布这篇文章后,我会立即投票给Chris,以及对另一个SO问题的回应.这是一些好东西!!!
使用我的图书馆The Helper Trinity:
public void SomeMethod(string firstName, string lastName, int age)
{
firstName.AssertNotNull("firstName");
lastName.AssertNotNull("lastName");
...
}
Run Code Online (Sandbox Code Playgroud)
还支持断言枚举参数是正确的,集合及其内容是非的null,字符串参数是非空的等等.有关详细示例,请参阅此处的用户文档.
| 归档时间: |
|
| 查看次数: |
3498 次 |
| 最近记录: |