When should I use Debug.Assert()?

后端 未结 20 1680
说谎
说谎 2020-11-30 16:12

I\'ve been a professional software engineer for about a year now, having graduated with a CS degree. I\'ve known about assertions for a while in C++ and C, but had no idea t

20条回答
  •  眼角桃花
    2020-11-30 17:01

    In Short

    Asserts are used for guards and for checking Design by Contract constraints, i.e. to ensure that the state of your code, objects, variables and parameters is operating within the boundaries and limits of your intended design.

    • 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.

    Assertions have enormous benefit:

    • To assist in finding missing validation of user inputs, or upstream bugs in higher level code.
    • Asserts in the code base clearly convey the assumptions made in the code to the reader
    • Assert will be checked at runtime in Debug builds.
    • Once code has been exhaustively tested, rebuilding the code as Release will remove the performance overhead of verifying the assumption (but with the benefit that a later Debug build will always revert the checks, if needed).

    ... More Detail

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

    When should you use Asserts?

    • 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 Code Contracts
    In the .Net Stack, Code Contracts can be used in addition to, or as an alternative to using Debug.Assert. Code Contracts can further formalize state checking, and can assist in detecting violations of assumptions at ~compile time (or shortly thereafter, if run as a background check in an IDE).

    Design by Contract (DBC) checks available include:

    • Contract.Requires - Contracted Preconditions
    • Contract.Ensures - Contracted PostConditions
    • Invariant - Expresses an assumption about the state of an object at all points in its lifespan.
    • Contract.Assumes - pacifies the static checker when a call to non-Contract decorated methods is made.

提交回复
热议问题