0

I have written this snippet and its contract:

[Pure]
public string getLevelName()
{
    using (var c = new myContext())
    {
        Contract.Ensures(Contract.Result<string>() == c.Level.FirstOrDefault(i => i.levelId == this.levelId).name);
        return c.Level.FirstOrDefault(i => i.levelId == this.levelId).name;
    }

}

but I get this error for contract:

Contract section within try block.

How can I avoid this error for this sort of contract for a method?

Majid
  • 13,853
  • 15
  • 77
  • 113
  • 4
    You should put all Contract.Requires() and Contract.Ensures() at the start of the method. If you cannot, then it's not something that's of use to the caller anyway - the assertion should be checkable using only the data passed to the method or by using public static methods. (Your example looks more like something that should be in a unit test.) – Matthew Watson Jan 07 '15 at 16:26
  • 6
    You shouldn't use contracts in this way - they are meant to be for validating the state of calls _to_ the method, usually parameters, not the interaction of what the method is _calling_. – Rhumborl Jan 07 '15 at 16:29
  • @Rhumborl I simply check that method works properly or not (virtually!)! – Majid Jan 07 '15 at 16:31
  • 1
    @Rhumborl is right about this particular contract, but people may need a solution to the general case. However, if you need to make sure the method works properly, you should use a unit test. – Jim Counts Jan 07 '15 at 16:33

3 Answers3

4

Try calling another method,

public string getLevelName()
{
    using (var c = new myContext())
    {
       return getLevelNameFrom(c);
    }

}

public string getLevelNameFrom(MyContext c)
{
        Contract.Ensures(Contract.Result<string>() == c.Level.FirstOrDefault(i => i.levelId == this.levelId).name);
        return c.Level.FirstOrDefault(i => i.levelId == this.levelId).name;
}
Jim Counts
  • 12,535
  • 9
  • 45
  • 63
1

You have to put all Contract.Ensures calls at the start of the method. The using statement is shorthand for a try finally block (the compiler extrapolates this for you).

Your code:

using (var c = new myContext())
{
    Contract.Ensures(Contract.Result<string>() == c.Level.FirstOrDefault(i => i.levelId == this.levelId).name);
    return c.Level.FirstOrDefault(i => i.levelId == this.levelId).name;
}

Turns into:

var c = new myContext();
try{
    Contract.Ensures(Contract.Result<string>() == c.Level.FirstOrDefault(i => i.levelId == this.levelId).name);
}
finally
{
    if (c != null)
        ((IDisposable)c).Dispose();
}

So essentially you are putting a Contract.Ensures call into a try block (just like the error is telling you). See this msdn article http://msdn.microsoft.com/en-us/library/dd412865.aspx in particular:

This method call must be at the beginning of a method or property, before any other code.

Kevin Holditch
  • 5,165
  • 3
  • 19
  • 35
1

Documentation says

This method call must be at the beginning of a method or property, before any other code.

In you sample

using (var c = new myContext())

would be transformed be compiler to

try 
{
  c = new myContext();
  Contract.Ensures ...
}
finally
{
   c.Dispose();
}

To avoid this use another private method and pass your context there

Max Brodin
  • 3,903
  • 1
  • 14
  • 23