0

I have started writing asserts into my code recently, but have discovered that with both Debug.Assert and Trace.Assert, the execution continues if the condition is not met. Is there an inbuilt equivalent that will throw an exception when the condition is not met? Or should I write my own? I want to throw an exception so that I don't continue to write something that is in an unexpected state.

EDIT: I have code somewhat like what is below. This is within a PUT request, so I want to update an existing resource (identified ideally by the Id, but also by a GUID in the case where a partial save occurred previously). If saving a new resource, then I want to ensure that a GUID is supplied.

public int Save(Guid? personGuid, Person person)
{
    if (person.Id > 0)
    {
        Update(person);
    }

    Trace.Assert(personGuid.HasValue);
    SaveToDb(personGuid, person);
}

NB: The Define TRACE constant option is checked.

mft25
  • 417
  • 6
  • 13
  • 2
    I'm not clear what you mean, are you talking about unit testing? Can you give some example code? – DavidG Mar 09 '20 at 10:05
  • `Trace.Assert` should throw an exception if the condition is not met always (and `Debug.Assert` should do the same, but only in Debug builds). Check that "Define TRACE constant" is checked in Project Properties -> Build – canton7 Mar 09 '20 at 10:06
  • @DavidG I've added some example code, I'm not talking about unit testing. – mft25 Mar 09 '20 at 10:18
  • @canton7 I have checked that this option is checked, but when running the build in Debug mode, the stack trace is output but no exception is thrown (ie. the execution continues). – mft25 Mar 09 '20 at 10:19
  • Do you want this code to be included in a production environment, so that it throws when bad data is supplied? – DavidG Mar 09 '20 at 10:20
  • @DavidG Yes, I want an exception to be thrown (with details of the assert statement) in all environments. – mft25 Mar 09 '20 at 10:21
  • Are you sure it doesn't just *seem* that the code continues? Do you have try/catch that swallows exceptions for instance? – Lasse V. Karlsen Mar 09 '20 at 10:21
  • @mft25 Can you clarify exactly what you mean by "the stack trace is output"? What exactly are you seeing, and where? – canton7 Mar 09 '20 at 10:21
  • If you add this: `Trace.Assert(false);`, then it should either run past that line silently if you don't have the correct #define or option checked (because the line wasn't even compiled into the assembly), or it should throw an exception. There is no third option. The fact that you see a stack trace means an exception was thrown, but I suspect you might have code or framework layers somewhere that swallows the exception. – Lasse V. Karlsen Mar 09 '20 at 10:22
  • @LasseV.Karlsen the behavior seems to depend on your settings according to the documentation https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.trace.assert?view=netcore-3.1 – mortb Mar 09 '20 at 10:24
  • 1
    `Trace.Assert` will allow you to step through the program when you debug through Visual Studio, but should throw an exception otherwise. – DavidG Mar 09 '20 at 10:26
  • @DavidG I will check if that is the cause, although that is behaviour I wouldn't have expected. In the meantime, here's a rextester that is similar to the issue I'm having (although I obviously have less control over the project settings). https://rextester.com/HBHRJ73592 – mft25 Mar 09 '20 at 10:31
  • @DavidG It seems this is the case (ie. different behaviour when launched via Visual Studio), but this is irritating as I like to test my code by launching from Visual Studio. – mft25 Mar 09 '20 at 10:41
  • Honestly, you should be testing with unit tests. Also, I'd recommend using an assertions library that makes all of this look a lot nicer, or write your own. – DavidG Mar 09 '20 at 10:43
  • @DavidG Do you know an assertion library that you would recommend? – mft25 Mar 09 '20 at 10:46

1 Answers1

2

The normal way would be to check the preconditions at the start of the method and simply throw an exception if they are not met. If there are checks that are common between many methods one pattern is to add a "ThrowIfInvalid" method and call it in all public methods.

There is also Code contracts that can assist in declaring preconditions and throwing if they fail. I.e.

Contract.Requires<ArgumentNullException>(personGuid.HasValue, "...");
JonasH
  • 28,608
  • 2
  • 10
  • 23
  • I bumped into [this problem](https://stackoverflow.com/questions/18793558/building-with-code-contracts) while trying this, and I think I will go with the accepted answer from that question and write my own custom asserter. Thanks for the recommendation. – mft25 Mar 09 '20 at 11:11