Debug.Assert puzzle!

E

emma middlebrook

I have a question regarding asserting ... here's some code:

string GetAssertMessage()
{
... prepare a message string and return it...
}

void SomeMethod()
{
...
Debug.Assert(condition, GetAssertMessage());
...
}

Even if condition is true, GetAssertMessage() will still be evaluated
as it's a parameter to a function. How can I best avoid the cost of
GetAssertMessage() if the condition is false and not in DEBUG mode? I
also read that I shouldn't really put function calls into an Assert
statement (MSDN "Assertions in Managed Code").

Idea 1:

#ifdef DEBUG

string GetAssertMessage()
{
... prepare a message string ...
}

#endif

void SomeMethod()
{
...
#ifdef DEBUG
if (!condition)
{
string message = GetAssertMessage();

// could use Debug.Fail without condition
Debug.Assert(condition, GetAssertMessage());
}
#endif
}

Surely there must be something a little more elegant than this? It
just makes the code ugly.

Any ideas or have I done the best I can here?

Thanks!

Emma Middlebrook
(e-mail address removed)
 
J

Jon Skeet [C# MVP]

emma middlebrook said:
I have a question regarding asserting ... here's some code:

string GetAssertMessage()
{
... prepare a message string and return it...
}

void SomeMethod()
{
...
Debug.Assert(condition, GetAssertMessage());
...
}

Even if condition is true, GetAssertMessage() will still be evaluated
as it's a parameter to a function. How can I best avoid the cost of
GetAssertMessage() if the condition is false and not in DEBUG mode? I
also read that I shouldn't really put function calls into an Assert
statement (MSDN "Assertions in Managed Code").

If you don't have DEBUG defined, it won't get evaluated at all. Here's
some sample code:

using System;
using System.Diagnostics;

public class Test
{
static void Main(string[] args)
{
Debug.Assert (true, GetMessage());
}

static string GetMessage()
{
Console.WriteLine ("GetMessage called");
return "message";
}
}

When DEBUG is defined, "GetMessage called" will be produced on the
console. When it's not, the message won't appear.
 
E

emma middlebrook

Jon

Thanks for your reply ...
If you don't have DEBUG defined, it won't get evaluated at all.

Yes, I got that far :) I was really more interested in whether anyone
had a better way than the below usage of the DEBUG symbol i.e. using
the preprocessor *as well as* testing for the condition *as well as*
using Debug.Fail or Debug.Assert in that block too! Something just
doesn't seem right about this code - looks a bit clumsy. Or am I
worrying too much?

#ifdef DEBUG
string GetAssertMessage()
{
... prepare a message string ...
}
#endif

void SomeMethod()
{
...
#ifdef DEBUG
if (!condition)
{
string message = GetAssertMessage();

// could use Debug.Fail without condition
Debug.Assert(condition, GetAssertMessage());
}
#endif
}

Thanks!

Emma Middlebrook
(e-mail address removed)
 
J

Jon Skeet [C# MVP]

emma middlebrook said:
Thanks for your reply ...


Yes, I got that far :) I was really more interested in whether anyone
had a better way than the below usage of the DEBUG symbol i.e. using
the preprocessor *as well as* testing for the condition *as well as*
using Debug.Fail or Debug.Assert in that block too! Something just
doesn't seem right about this code - looks a bit clumsy. Or am I
worrying too much?

I think you're worrying too much - what's wrong with just:

Debug.Assert (condition, GetAssertMessage());

?

GetAssertMessage doesn't get invoked when DEBUG isn't defined, so
what's the disadvantage? You end up with a *slightly* larger assembly
(as the method is still present) but it'll never even be JITted.
 
M

mikeb

emma said:
Jon

Thanks for your reply ...




Yes, I got that far :) I was really more interested in whether anyone
had a better way than the below usage of the DEBUG symbol i.e. using
the preprocessor *as well as* testing for the condition *as well as*
using Debug.Fail or Debug.Assert in that block too! Something just
doesn't seem right about this code - looks a bit clumsy. Or am I
worrying too much?

#ifdef DEBUG
string GetAssertMessage()
{
... prepare a message string ...
}
#endif

void SomeMethod()
{
...
#ifdef DEBUG
if (!condition)
{
string message = GetAssertMessage();

// could use Debug.Fail without condition
Debug.Assert(condition, GetAssertMessage());
}
#endif
}


You could write your own Assert() wrapper method, decorate it with the
ConditionalAttribute so it only gets called when DEBUG is defined:

public class MyDebug {
[System.Diagnostics.ConditionalAttribute( "DEBUG")]
public static void Assert( bool condition) {
if (!condition) {
string msg = GetAssertMessage();
System.Diagnostics.Debug.Assert(condition, msg);
}
}
}


Now, replace your Debug.Assert() calls with calls to MyDebug.Assert().
GetAssertMessage() will only be evaluated when the assertion condition
fails, and the ConditionalAttribute tells the compiler to not bother
putting the IL for calls to the MyDebug.Assert() method in the assembly
unless DEBUG is defined.

Depending on the deployment requirements of your application, and
whether or not calls to MyDebug.Assert are made from different
assemblies than where MyDebug is implemented, you may want to place the
*body* (not the entire definition) of MyAssert() inside an "#if DEBUG"
block, because the ConditionalAttribute only affects the calls to the
method - the method itself still gets compiled to IL, regardless of the
build type.

You might want to decorate GetAssertMessage() with the conditional
attribute as well, instead of placing it inside an "#if DEBUG" block.

Now that I mentioned that, I'll bet one reason you asked this question
is because you get compiler errors when calls to GetAssertMessage() are
not inside an "#if DEBUG" block. Simply using the ConditionalAttribute
on it will fix that problem.

If your problem is really that actual runtime calls to
GetAssertMessage() are too expensive in a DEBUG build, then you will
probably need to go with my first suggestion.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top