Am I implementing this simple contract incorrectly?
Asked Answered
M

1

17

This is my code:

public class RegularPolygon
{
    public int VertexCount;
    public double SideLength;

    public RegularPolygon(int vertexCount, double sideLength)
    {
        Contract.Requires(vertexCount >= 3);
        VertexCount = vertexCount;
        SideLength = sideLength;
    }

    [ContractInvariantMethod]
    private void RegularPolygonInvariants()
    {
        Contract.Invariant(VertexCount>=3);
    }

}

I have tried with both the Contract.Requires and Contract.Invariant methods to prevent the vertexCount variable from becoming less than or equal to 2; however I am still able to initialise a RegularPolygon with 2 or fewer sides. My (simplified) NUnit test looks like this:

[TestFixture]
class TestRegularPolygon
{
    private RegularPolygon _polygon;

    [SetUp]
    public void Init()
    {
        _polygon = new RegularPolygon(1, 50);
    }

    [Test]
    public void Constructor()
    {
        Assert.That(_polygon.VertexCount,Is.GreaterThanOrEqualTo(3));
    }

}

The above test also passes and I cannot figure out why!

At first I thought ReSharper might have been messing something up because it greys out the line and displays this message whenever I try to use a method in the Contract namespace:

Method invocation is skipped. Compiler will not generate method invocation because the method is conditional, or it is partial method without implementation.

But suspending R# and running the tests in NUnit has the same result with no errors or warnings in VS either. So I assume that is just because ReSharper does not have highlighting compatibility for code contracts yet.

I have looked at the documentation and as far as I can tell I shouldn't be having this problem.

Am I using code contracts incorrectly or is my environment preventing it from working somehow?

Thank you.

Moraceous answered 11/8, 2010 at 19:18 Comment(0)
R
19

First thing to check - have you actually got contract checking turned on? If not, none of your contracts will do anything. That would explain the R# warning, too. Look under "Code Contracts" in the build properties, and see what it says under "Runtime Checking".

As per comments, ensure you have CONTRACTS_FULL defined as a compilation symbol - that appears to be what R# requires.

Second point: you've got public mutable fields, which means your invariant can be violated at any moment by someone writing

polygon.VertexCount = 0;

Please don't use public fields, particularly not writable ones. :)

Rewrite answered 11/8, 2010 at 19:20 Comment(8)
Wouldnt the invariant method catch that? I thought that's what theyre for. The above is not my complete code, just an example to demonstrate my problem. If by turning on contract checking you mean going to the project properties > Code Contracts > static checking/full runtime checking, yes they are turned on now (they were not before) but I still have the same problem.Moraceous
@rmx: Invariant methods aren't going to run when you just change fields. How could they? There's no code for them to hook into, unless the calling code was modified. Now, in terms of having "the same problem" - do you have all the same symptoms? Is R# still greying out the line?Rewrite
OK, cancel that. I have it working. My Invariant methods needed to be private as well. Still got the R# message and greyed out line but it doesnt seem to be affecting the functionality of the contracts. Hopefully they fix that in the next release.Moraceous
@rmx: Goodo :) Sorry for missing that the invariant has to be private. If you want R# to stop complaining, you could explicitly define CONTRACTS_FULL in your project - I suspect that the Code Contracts plug-in is defining that preprocessor symbol in a way that R# can't detect :(Rewrite
Thanks Jon (once again). I'll look into fixing the r# message - I've done some poking around and some other people seem to have the same thing.Moraceous
Changing <DefineConstants>DEBUG;TRACE</DefineConstants> in the csproj files to <DefineConstants>DEBUG;TRACE;CONTRACTS_FULL</DefineConstants> has got rid of the r# issue. TYMoraceous
@rmx 's answer should be promoted to a full answer.Tracheid
@stricq: Will add it into this one.Rewrite

© 2022 - 2024 — McMap. All rights reserved.