32

consider the following two pieces of code:

    public static Time Parse(string value)
    {
        string regXExpres = 
           "^([0-9]|[0-1][0-9]|2[0-3]):([0-9]|[0-5][0-9])$|^24:(0|00)$";
        Contract.Requires(value != null);
        Contract.Requires(new Regex(regXExpres).IsMatch(value));
        string[] tokens = value.Split(':');
        int hour = Convert.ToInt32(tokens[0], CultureInfo.InvariantCulture);
        int minute = Convert.ToInt32(tokens[1], CultureInfo.InvariantCulture);
        return new Time(hour, minute);
    }

and

    public static Time Parse(string value)
    {
        if (value == null)
        {
            throw new ArgumentNullException("value");
        }
        string[] tokens = value.Split(':');
        if (tokens.Length != 2)
        {
            throw new FormatException("value must be h:m");
        }
        int hour = Convert.ToInt32(tokens[0], CultureInfo.InvariantCulture);
        if (!(0 <= hour && hour <= 24))
        {
            throw new FormatException("hour must be between 0 and 24");
        }
        int minute = Convert.ToInt32(tokens[1], CultureInfo.InvariantCulture);
        if (!(0 <= minute && minute <= 59))
        {
            throw new FormatException("minute must be between 0 and 59");
        }
        return new Time(hour, minute);
    }

I personally prefer the first version because the code is much clearer and smaller, and the Contracts can be easily turned off. But the disadvantage is that Visual Studio Code Analysis blames that I should check the parameter value for null and the Contracts of the constructor do not realize that the regex ensures that minute and hour are within the given boundarys.

So i end up having a lot of wrong warnings and I see no way to validate string values with contracts without ending up throwing FormatExceptions other than a RegEx validation.

Any suggestions how you would solve this and equivalent situations using Code contracts?

steveee
  • 321
  • 3
  • 8
  • 1
    You do realise that you could rewrite the second example to use the same regular expression, right? That would make both examples more similar than not. – Robert Koritnik Oct 16 '13 at 07:40

1 Answers1

21

In order to get rid of warnings you can use Contract.Assume

Dzmitry Huba
  • 4,493
  • 20
  • 19
  • this sort of solves my problem. If I add the following lines in front of the return statement all the wrong warnings are gone. The only thing I still do not really like is that these lines are somehow blowing up the code. But I guess it's impossible for code contracts to get the meaning of regular expressions. Contract.Assume(0 <= hour && hour <= 24); Contract.Assume(0 <= minute && minute <= 59); – steveee Dec 30 '09 at 15:42
  • 15
    @steveee, you should always split contracts on conjunctions, so that `Contract.Assume(0 <= hour && hour <= 24);` becomes `Contract.Assume(0 <= hour); Contract.Assume(hour <=24);` – porges Jan 25 '10 at 00:51
  • @Porges is there a document explaining why? – Sedat Kapanoglu Oct 18 '13 at 17:24
  • 3
    @ssg: I don't think it's in the documentation but if you search the Code Contracts MSDN forum there is information from the devs, e.g.: "splitting conjunctions into different contracts makes the static checker more precise, and you get better error messages." – porges Oct 19 '13 at 03:46