2015-04-10 1 views
0

я получаю эти предупреждения от CodeContracts:CodeContracts: Доступ к массиву может быть выше верхней границы

Доступ к массиву может быть выше верхней границы. Вы имели в виду 0 вместо 1?
Доступ к массиву может быть выше верхней границы. Вы имели в виду 1 вместо 2?
Доступ к массиву может быть выше верхней границы. Вы имели в виду 2 вместо 3?
Доступ к массиву может быть выше верхней границы. Вы имели в виду 3 вместо 4?

На этой строке кода:

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]; 
    } 
} 

Как рассказать Contracts анализатор, что эти показатели гарантированы в пределах? _addr инициализируется в конструкторе до string[4].

+0

Не могли бы вы показать нам, куда обращаются «AddressLine1» и где в конструкторе '_addr' инициализируется? –

+0

Ваш код кажется немного странным для меня. Мне просто интересно, почему нижние индексы ноль, но более высокие могут быть не такими. – ryanyuyu

+0

Причина в том, что у нас есть два других свойства, подобные этому. См. Мое редактирование. – Amy

ответ

4

Я был в состоянии избавиться от этих предупреждений путем добавления метода к этому классу, который определил инварианты:

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

Однако, я думаю, что есть также ошибка в коде.

Если _addr[0] == null и _addr[1] != null, то AddressLine1 и AddressLine2 возвращают те же значения. Это похоже на ошибку.

Вы можете исправить это довольно легко (и устранить необходимость указывать контрактные инварианты), используя что-то вдоль линий, что @ryanyuyu отметил:

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(); 
    } 
} 
+0

А, это сделал инвариант. – Amy

-1

Я не знаю анализатора контрактов, но ваш код может быть чище. Вы в основном повторяете код, который просто находит первую ненулевую строку (и если последний элемент имеет значение null, вы возвращаете это независимо). Я поклонник использования LINQ .FirstOrDefault, который позволит вам найти первый элемент, соответствующий условию (в вашем случае не null). Если такой элемент не найден, то возвращается значение по умолчанию (для строки это null)

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

в действии на этом .NET Fiddle.

+0

Это не отвечает на вопрос. Да, я знаю, что могу использовать LINQ. Этот вопрос конкретно касается кодовых контрактов. – Amy

0

ContractInvariantMethod работает, когда _addr является членом класса. Но Contract.Assert() также работает с локальными переменными.

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]; 
} 
Смежные вопросы