到目前为止,我已经做了一年的专业软件工程师,并获得了计算机科学学位。我知道c++和C中的断言有一段时间了,但直到最近才知道它们存在于c#和。net中。
我们的生产代码不包含任何断言,我的问题是这个…
我应该开始在我们的生产代码中使用断言吗?如果可以,什么时候使用它最合适?这样做会更有意义吗
Debug.Assert(val != null, "message");
or
if ( val == null )
throw new exception("message");
到目前为止,我已经做了一年的专业软件工程师,并获得了计算机科学学位。我知道c++和C中的断言有一段时间了,但直到最近才知道它们存在于c#和。net中。
我们的生产代码不包含任何断言,我的问题是这个…
我应该开始在我们的生产代码中使用断言吗?如果可以,什么时候使用它最合适?这样做会更有意义吗
Debug.Assert(val != null, "message");
or
if ( val == null )
throw new exception("message");
当前回答
我不会在产品代码中使用它们。抛出异常,捕获和记录。
在asp.net中也需要小心,因为断言可以显示在控制台上并冻结请求。
其他回答
我不知道它在c#和。net中是怎样的,但在C中assert()只在使用- ddebug编译时工作-如果没有编译,最终用户将永远不会看到assert()。仅供开发人员使用。我经常使用它,它有时更容易跟踪错误。
您应该使用Debug。断言来测试程序中的逻辑错误。编译器只能通知您语法错误。因此,您肯定应该使用Assert语句来测试逻辑错误。比如测试一个销售汽车的项目,只有蓝色的宝马可以得到15%的折扣。编译器不能告诉你你的程序在执行这个操作时逻辑上是否正确,但是assert语句可以。
所有的断言应该是代码,可以优化为:
Debug.Assert(true);
因为它检验的是你已经假设为真的东西。例如:
public static void ConsumeEnumeration<T>(this IEnumerable<T> source)
{
if(source != null)
using(var en = source.GetEnumerator())
RunThroughEnumerator(en);
}
public static T GetFirstAndConsume<T>(this IEnumerable<T> source)
{
if(source == null)
throw new ArgumentNullException("source");
using(var en = source.GetEnumerator())
{
if(!en.MoveNext())
throw new InvalidOperationException("Empty sequence");
T ret = en.Current;
RunThroughEnumerator(en);
return ret;
}
}
private static void RunThroughEnumerator<T>(IEnumerator<T> en)
{
Debug.Assert(en != null);
while(en.MoveNext());
}
在上面,有三种不同的空参数方法。第一个接受它为允许的(它只是什么都不做)。第二个则抛出异常供调用代码处理(或不处理,导致错误消息)。第三种假设它不可能发生,并断言它是这样的。
在第一种情况下,没有问题。
在第二种情况下,调用代码有一个问题——它不应该用null调用GetFirstAndConsume,所以它会返回一个异常。
在第三种情况下,这段代码有一个问题,因为在调用它之前,它应该已经检查过en != null,所以它不是真的是一个错误。或者换句话说,它应该是理论上可以优化为Debug.Assert(true)的代码,sicne en != null应该始终为真!
断言用于捕获程序员(您的)错误,而不是用户错误。只有在用户不可能触发断言时才应该使用它们。例如,如果你正在编写一个API,在API用户调用的任何方法中,都不应该使用断言来检查参数是否为空。但是它可以在一个私有方法中使用,而不是作为API的一部分公开,以断言您的代码永远不会在不应该传递null参数时传递null参数。
当我不确定时,我通常更喜欢异常而不是断言。
简而言之
断言用于保护和检查契约式设计约束,即确保代码、对象、变量和参数的状态在预期设计的边界和限制内运行。
Asserts should be for Debug and non-Production builds only. Asserts are typically ignored by the compiler in Release builds. Asserts can check for bugs / unexpected conditions which ARE in the control of your system Asserts are NOT a mechanism for first-line validation of user input or business rules Asserts should not be used to detect unexpected environmental conditions (which are outside the control of the code) e.g. out of memory, network failure, database failure, etc. Although rare, these conditions are to be expected (and your app code cannot fix issues like hardware failure or resource exhaustion). Typically, exceptions will be thrown - your application can then either take corrective action (e.g. retry a database or network operation, attempt to free up cached memory), or abort gracefully if the exception cannot be handled. A failed Assertion should be fatal to your system - i.e. unlike an exception, do not try and catch or handle failed Asserts - your code is operating in unexpected territory. Stack Traces and crash dumps can be used to determine what went wrong.
断言有巨大的好处:
帮助查找用户输入的缺失验证,或高级代码中的上游错误。 代码库中的断言清楚地向读者传达了代码中所做的假设 Assert将在调试版本的运行时进行检查。 一旦对代码进行了详尽的测试,将代码重新构建为Release将消除验证假设的性能开销(但好处是,如果需要,后面的Debug构建将始终恢复检查)。
... 更详细地
Debug.Assert expresses a condition which has been assumed about state by the remainder of the code block within the control of the program. This can include the state of the provided parameters, state of members of a class instance, or that the return from a method call is in its contracted / designed range. Typically, asserts should crash the thread / process / program with all necessary info (Stack Trace, Crash Dump, etc), as they indicate the presence of a bug or unconsidered condition which has not been designed for (i.e. do not try and catch or handle assertion failures), with one possible exception of when an assertion itself could cause more damage than the bug (e.g. Air Traffic Controllers wouldn't want a YSOD when an aircraft goes submarine, although it is moot whether a debug build should be deployed to production ...)
什么时候应该使用断言?
At any point in a system, or library API, or service where the inputs to a function or state of a class are assumed valid (e.g. when validation has already been done on user input in the presentation tier of a system, the business and data tier classes typically assume that null checks, range checks, string length checks etc on input have been already done). Common Assert checks include where an invalid assumption would result in a null object dereference, a zero divisor, numerical or date arithmetic overflow, and general out of band / not designed for behaviour (e.g. if a 32 bit int was used to model a human's age, it would be prudent to Assert that the age is actually between 0 and 125 or so - values of -100 and 10^10 were not designed for).
.Net代码契约 在. net堆栈中,代码契约可以作为Debug.Assert的补充,也可以作为Debug.Assert的替代。代码契约可以进一步形式化状态检查,并且可以帮助在编译时(或者稍后,如果在IDE中作为背景检查运行)检测违反假设的情况。
契约式设计(DBC)检查包括:
合同。要求-约定的先决条件 合同。保证-合同后置条件 不变量——表示关于对象在其生命周期中所有点的状态的假设。 合同。当调用非契约装饰方法时,假定-安抚静态检查器。