When should I use Debug.Assert()?

后端 未结 20 1547
说谎
说谎 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 16:57

    Quote Taken from The Pragmatic Programmer: From Journeyman to Master

    Leave Assertions Turned On

    There is a common misunderstanding about assertions, promulgated by the people who write compilers and language environments. It goes something like this:

    Assertions add some overhead to code. Because they check for things that should never happen, they'll get triggered only by a bug in the code. Once the code has been tested and shipped, they are no longer needed, and should be turned off to make the code run faster. Assertions are a debugging facility.

    There are two patently wrong assumptions here. First, they assume that testing finds all the bugs. In reality, for any complex program you are unlikely to test even a miniscule percentage of the permutations your code will be put through (see Ruthless Testing).

    Second, the optimists are forgetting that your program runs in a dangerous world. During testing, rats probably won't gnaw through a communications cable, someone playing a game won't exhaust memory, and log files won't fill the hard drive. These things might happen when your program runs in a production environment. Your first line of defense is checking for any possible error, and your second is using assertions to try to detect those you've missed.

    Turning off assertions when you deliver a program to production is like crossing a high wire without a net because you once made it across in practice. There's dramatic value, but it's hard to get life insurance.

    Even if you do have performance issues, turn off only those assertions that really hit you.

    0 讨论(0)
  • 2020-11-30 16:57

    You should always use the second approach (throwing exceptions).

    Also if you're in production (and have a release-build), it's better to throw an exception (and let the app crash in the worst-case) than working with invalid values and maybe destroy your customer's data (which may cost thousand of dollars).

    0 讨论(0)
  • 2020-11-30 16:59

    FWIW ... I find that my public methods tend to use the if () { throw; } pattern to ensure that the method is being called correctly. My private methods tend to use Debug.Assert().

    The idea is that with my private methods, I'm the one under control, so if I start calling one of my own private methods with parameters that are incorrect, then I've broken my own assumption somewhere--I should have never gotten into that state. In production, these private asserts should ideally be unnecessary work since I am supposed to be keeping my internal state valid and consistent. Contrast with parameters given to public methods, which could be called by anyone at runtime: I still need to enforce parameter constraints there by throwing exceptions.

    Additionally, my private methods can still throw exceptions if something doesn't work at runtime (network error, data access error, bad data retrieved from a third party service, etc.). My asserts are just there to make sure that I haven't broken my own internal assumptions about the state of the object.

    0 讨论(0)
  • 2020-11-30 17:01

    From Code Complete

    8 Defensive Programming

    8.2 Assertions

    An assertion is code that’s used during development—usually a routine or macro—that allows a program to check itself as it runs. When an assertion is true, that means everything is operating as expected. When it’s false, that means it has detected an unexpected error in the code. For example, if the system assumes that a customer-information file will never have more than 50,000 records, the program might contain an assertion that the number of records is lessthan or equal to 50,000. As long as the number of records is less than or equal to 50,000, the assertion will be silent. If it encounters more than 50,000 records, however, it will loudly “assert” that there is an error in the program.

    Assertions are especially useful in large, complicated programs and in high reliability programs. They enable programmers to more quickly flush out mismatched interface assumptions, errors that creep in when code is modified, and so on.

    An assertion usually takes two arguments: a boolean expression that describes the assumption that’s supposed to be true and a message to display if it isn’t.

    (…)

    Normally, you don’t want users to see assertion messages in production code; assertions are primarily for use during development and maintenance. Assertions are normally compiled into the code at development time and compiled out of the code for production. During development, assertions flush out contradictory assumptions, unexpected conditions, bad values passed to routines, and so on. During production, they are compiled out of the code so that the assertions don’t degrade system performance.

    0 讨论(0)
  • 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.
    0 讨论(0)
  • 2020-11-30 17:02

    In Debugging Microsoft .NET 2.0 Applications John Robbins has a big section on assertions. His main points are:

    1. Assert liberally. You can never have too many assertions.
    2. Assertions don't replace exceptions. Exceptions cover the things your code demands; assertions cover the things it assumes.
    3. A well-written assertion can tell you not just what happened and where (like an exception), but why.
    4. An exception message can often be cryptic, requiring you to work backwards through the code to recreate the context that caused the error. An assertion can preserve the program's state at the time the error occurred.
    5. Assertions double as documentation, telling other developers what implied assumptions your code depends on.
    6. The dialog that appears when an assertion fails lets you attach a debugger to the process, so you can poke around the stack as if you had put a breakpoint there.

    PS: If you liked Code Complete, I recommend following it up with this book. I bought it to learn about using WinDBG and dump files, but the first half is packed with tips to help avoid bugs in the first place.

    0 讨论(0)
提交回复
热议问题