12

I just tried to use Code Contracts, and I see no real advantages over an if statement.

Consider the following.

private static void BindClassesToInterfacesByConvention(string classesEndingWith
    , string interfacesEndingwith) {
    Contract.Requires<ArgumentNullexception>(
        string.IsNullOrWhiteSpace(classesEndingWith)
        , "classesEndingWith");

    Contract.Requires<ArgumentNullException>(
        string.IsNullOrWhitespace(interfacesEndingWith)
        , "interfacesendingWith");

    ...
}

I find it way more confusing than simply using an if statement

private static void BindClassesToInterfacesByConvention(string classesEndingWith
    , string interfacesEndingwith) {
    if (string.IsNullOrWhiteSpace(classesEndingWith)) 
        throw new ArgumentNullException("classesEndingWith");

    if (string.IsNullOrWhitespace(interfacesEndingWith))
        throw new ArgumentNullException("interfacesendingWith");

    ...
}

Code Contracts are supposed to warn me at compile time that a a contract is violated. So, I was expecting to get an error or a warning when I have written the following.

BindClassesToInterfacesByConvention(null, null);

And nothing happened, everything compiled just fine, and neither an error nor a warning message appeared.

In this scenario, I believe it is best to continue with the it statement. Or perhaps was it an unfair use of Code Contracts?

Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
  • 3
    There are more advantages to Code Contracts than just the syntax. They're actually listed up front in the [Code Contracts docs](http://msdn.microsoft.com/en-us/library/dd264808(v=vs.110).aspx). Static analysis is a particularly big deal, and very hard to get right by analyzing `if` statements. – Paul Roub Sep 11 '14 at 20:38
  • "warn me at compile time"... that was my misconception too; but it turned out it is effectively a separate program (Vs addon) that analyses your code and takes a while to do so. – Meirion Hughes Sep 11 '14 at 20:49

4 Answers4

6

Code Contracts are a great idea let down by tooling that isn't quite there. Firstly, in order to make the exceptions actually throw, you have to install the right extensions in Visual Studio and/or configure the correct settings on your project. Great fun if you have unit tests relying on the code contracts throwing exceptions at runtime and run them on a build server.

However, it is important to understand that the real purpose of Code Contracts isn't just to throw exceptions. It enables static code analysis (if you switch it on), which when enabled may be able to give you an error at compile time - but it does require you to do a lot of work to apply it pretty much everywhere in order for the static code analysis to really work. I believe that is the scenario you are trying to test? In which case I suggest you look at the code contracts setting for your project to make sure you have enabled all the static code checking (it will make your build rather long).

Furthermore and importantly, the code contracts allows you to communicate intent to the callers of your methods; Intellisense will pick up on the conditions you have specified (provided you install the correct extensions). The informatation about the code contracts can also automatically be added to the XML file that can accompany assemblies, which will then enable 3rd party users of your assembly to know about your requirements when they write their code, as well as allowing you to include this information in helpfiles built with Sandcastle etc.

It's a great idea, just not really fully implemented in the tools yet so you get some funny behavior once in a while. Personally I have pretty much stopped using them for the time being.

flytzen
  • 7,348
  • 5
  • 38
  • 54
3

You are specifying a method that requires its arguments to be null or whitespace, then passing null. The contract is satisfied. That's why you got no contract violation. (Requires() requires throws the exception when the condition evaluates to false, not to true.)

Furthermore, even if you correct the contract, you shouldn't be throwing ArgumentNullException if the parameter value is a non-null string containing no characters or only whitespace characters. In that case you should throw an ArgumentException.

I would do this:

private static void BindClassesToInterfacesByConvention(string classesEndingWith
    , string interfacesEndingwith) {
    Contract.Requires<ArgumentNullException>(classesEndingWith != null
        , "classesEndingWith");

    Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(classesEndingWith)
        , "classesEndingWith");

    Contract.Requires<ArgumentNullException>(interfacesEndingWith != null
        , "interfacesEndingWith");

    Contract.Requires<ArgumentException>(!string.IsNullOrWhiteSpace(interfacesEndingWith)
        , "interfacesEndingWith");

    ...
}

To download the Code Contracts analysis tools, including Visual Studio integration, visit http://visualstudiogallery.msdn.microsoft.com/1ec7db13-3363-46c9-851f-1ce455f66970

phoog
  • 42,068
  • 6
  • 79
  • 117
  • I have corrected my code to apply your suggested changes, and still, nothing happens when I compile. – Will Marcouiller Sep 11 '14 at 20:38
  • @WillMarcouiller do you have Code Contracts VS extension installed, and contracts enabled in project properties' page? – Matías Fidemraizer Sep 11 '14 at 20:39
  • @WillMarcouiller have you set the static checking options on the code contracts tab of the project properties? See this article for an out-of-date image that should be helpful nonetheless: http://msdn.microsoft.com/en-us/magazine/hh148151.aspx – phoog Sep 11 '14 at 20:39
  • This must be the issue. I have no Code Contracts tab in my project properties. The only tabs I got are: `Application`, `Build`, `Debug`, `Resources`, `Services`, `Settings`, `References`, `Signature`, `Security`, `Publish`. Could you please walk me through? – Will Marcouiller Sep 11 '14 at 20:43
  • @WillMarcouiller I added a link for the download page in my answer. – phoog Sep 11 '14 at 20:45
  • I've been able to walk through the setup process and work with contracts. However, it seems they don't actually do what I expected them to do, because in some tests, I expressly put some null values into method calls which require non-null values, and nothing happens on compile-time. Perhaps do I not understand clearly how to use them. I shall dig deeper another time on, and see what I can find. I ended up not using them. – Will Marcouiller Sep 15 '14 at 13:11
  • @WillMarcouiller If you are looking for the build to fail when contracts are violated, there is a setting for that. If that box is not checked, you just get compiler warnings and messages. But if you pass null to a parameter that has a contract requiring it not to be null, you should definitely be getting at least the warning; if you're not, something is wrong either with your code or with the CC settings for the project. – phoog Sep 16 '14 at 07:42
  • Thanks for this information. I will see if there's a check box somewhere that I forgot to use or whatever. =) – Will Marcouiller Sep 16 '14 at 12:11
1

This is a subjective answer, but I would say the real statement here is: "I just tried to use Code Contracts, and I see no real advantages over a Unit Test"

For Example:

private void Foo(string something) 
{
    Contract.Requires<ArgumentNullException>(something != null, "something");
}

is equivalent as (NUnit testing):

void Foo(string something) 
{
    if (something == null) 
        throw new ArgumentNullException();
}

[Test]
[ExpectedException( typeof( ArgumentNullException ) )]
void foo_throws_exception_with_null_param() 
{
    Foo(null);
}

Which is better? Well from my (limited) experience the static analysis addon for VS is quite slow. If you have done a call to foo with an explicit null'ed variable then it'll pick it up. But it won't pick up nulls loaded dynamically and send to foo during user iteraction.

On the other hand, if you have an if-statement and a unit test to ensure it WILL throw an ArgumentNullException then you know that the exception is going to be thrown; and you can deal with it in the run-time environment... you can test anything that uses Foo to make sure it handles the exception.

Ensuring that explicit check is very fast with NUnit. The downside of unit testing is setting up the tests to begin with. So my opinion is that over time you'll save more time by being explicit, making unit tests and ensuring your application can handle if those exceptions are thrown... it'll just cost you more to begin with to set it up.

Meirion Hughes
  • 24,994
  • 12
  • 71
  • 122
  • `But it won't pick up nulls loaded dynamically and send to foo during user iteraction. ` It will, actually. That is why `Contract.Ensures` is important, because you can declare that some method will never return null, and code contracts picks up this information to infer what can happen in those cases. – julealgon Mar 24 '15 at 22:41
0

Yes, Code Contracts will warn you at compile time that a a contract is violated if you enable the static checking.It proved the Code Contract add-ons(Code Contracts for .NET)only works on Visual Studio 2013 or lower versions, but not Visual Studio 2015 or 2017.

On Visual Studio 2013: enter image description here

On Visual Studio 2015, we can see the error information from Output window, but not in Error List window. This bug was already logged and fixed, but it can still be repro.Warnings and messages from static contract checking don't appear in the VS2015 error list enter image description here


Latest update:
Install the latest Contracts.devlab9ts.msi(Currently, it's just RC version) will resolve the issue in Visual Studio 2015. DotNet CodeContracts v.1.10.20606.1-rc2 enter image description here

Johnny Qian
  • 668
  • 7
  • 14