0

I'm getting these warnings from CodeContracts:

Array access might be above the upper bound. Did you meant 0 instead of 1?
Array access might be above the upper bound. Did you meant 1 instead of 2?
Array access might be above the upper bound. Did you meant 2 instead of 3?
Array access might be above the upper bound. Did you meant 3 instead of 4?

On this line of code:

private readonly string[] _addr;

public string AddressLine1
{
    get
    {
        return _addr[0] ?? _addr[1] ?? _addr[2] ?? _addr[3];
    }
}

public string AddressLine2
{
    get
    {
        return _addr[1] ?? _addr[2] ?? _addr[3];
    }
}

public string AddressLine3
{
    get
    {
        return _addr[2] ?? _addr[3];
    }
}

How do I tell the Contracts analyzer that these indices are guaranteed inside bounds? _addr is initialized in the constructor to string[4].

  • Could you please show us where `AddressLine1` is being accessed and where in the constructor `_addr` is initialized? – John Odom Apr 10 '15 at 22:20
  • Your code seems just a bit strange to me. I'm just wondering why the lower indices are null but the higher ones might not be. – ryanyuyu Apr 10 '15 at 22:21
  • The reason its like that is we have two other properties just like it. See my edit. –  Apr 11 '15 at 01:43
  • @ryanyuyu, because that's how we're getting them from another system. –  Apr 11 '15 at 01:45

3 Answers3

4

I was able to get rid of these warnings by adding a method to that class that defined the invariants:

[ContractInvariantMethod]
private void AddressInvariants()
{
    Contract.Invariant(_addr.Length == 4);
}

However, I think there's also a bug in your code.

If _addr[0] == null and _addr[1] != null, then AddressLine1 and AddressLine2 return the same value. This seems like a bug.

You can fix this easily enough (and remove the need to specify contract invariants) by using something along the lines of what @ryanyuyu mentioned:

public string AddressLine1
{
    get
    {
        // Use the first non-null element.
        return _addr.Where(x => x != null).FirstOrDefault();
    }
}

public string AddressLine2
{
    get
    {
        // Use the second non-null element.
        return _addr.Where(x => x != null).Skip(1).FirstOrDefault();
    }
}

public string AddressLine3
{
    get
    {
        // Use the third non-null element.
        return _addr.Where(x => x != null).Skip(2).FirstOrDefault();
    }
}
reduckted
  • 2,358
  • 3
  • 28
  • 37
0

ContractInvariantMethod works when _addr is a class member. But Contract.Assert() works with local variables too.

static void MyParse(string foo)
{
    string[] split = foo.Split(',');
    Contract.Assert(split.Length == 4);

    string a = split[0];
    string b = split[1];
    string c = split[2];
    string d = split[3];
}
piedar
  • 2,599
  • 1
  • 25
  • 37
-1

I don't know about the Contracts analyzer, but your code could be cleaner. You are basically repeating code that just finds the first non-null string (and if the last element is null, you are returning that regardless). I'm a fan of using LINQ .FirstOrDefault which will let you find the first element that matches a condition (in your case not null). If no such element is found, it returns the default value (for a String it's null)

return _addr.FirstOrDefault(str => str != null);

See it in action at this .NET Fiddle.

ryanyuyu
  • 6,366
  • 10
  • 48
  • 53
  • This doesn't answer the question, though. Yes, I know I can use LINQ. This question is specifically about Code Contracts. –  Apr 11 '15 at 01:43