#c#-4.0 #code-contracts #design-by-contract
#c #-4.0 #кодовые контракты #разработка по контракту
Вопрос:
Я создал метод, подобный этому
class PersonCollection
{
[Contracts.CanReturnNull] //dont know if something like this exists?
IPerson GetPerson(Guid personId)
{
if (this.persons.Contains(personId))
return this.persons[personId];
else
return null;
}
}
Теперь вызывающий код должен правильно обработать значение null. Есть ли способ выразить контракт для всех вызывающих, который им нужен, чтобы иметь возможность обрабатывать нулевое значение, возвращаемое этим методом?
PersonCollection pc = new PersonCollection();
IPerson p = pc.GetPerson(anyId);
p.Name = "Hugo"; // here I want to have a curly line
Чего я хочу, так это чтобы p был помечен как потенциально проблемный.
РЕДАКТИРОВАТЬ Я просто изменил код и добавил вызывающий код и ожидаемое поведение. Также я добавил атрибут, который, вероятно, не существует в методе GetPerson
Комментарии:
1. В C # переменные ссылочного типа имеют
null
значение по умолчанию. Если только контракт неGetPerson
гарантирует, чтоIPerson
значение не равно null, вызывающий должен учитывать возможностьnull
возврата.2. Я бы рекомендовал изменить имя вашего метода на GetPersonOrNull , если вы хотите дать понять вызывающему, что он может получить нулевое значение.
Ответ №1:
Code Contract не предоставляет такой функции, как и C#
Кодовые контракты требуют от вызывающего только соблюдения определенных ограничений в начале вызываемого метода. Это так называемые предварительные условия. За постусловия отвечает вызываемый объект и определяет, в каком состоянии будет программа при выходе из вызываемого метода.
Проектирование по контракту — это способ определить эти обязанности, а не указывать вызывающим пользователям, как они должны обрабатывать определенные условия, вызванные вызываемым методом.
Комментарии:
1. 1: Кодовые контракты позволяют указывать «этот параметр не может быть нулевым» в качестве предварительного условия или «это возвращаемое значение не будет нулевым» в качестве последующего условия.
Ответ №2:
То, что вы, кажется, хотите (после прочтения комментариев), произойдет по умолчанию:
Если вы включите кодовые контракты в вызывающем коде, верификатор сочтет, что возвращаемое значение GetPerson()
может быть нулевым. Итак:
IPerson GetPerson(Guid personId)
{
// no pre/post conditions
}
void PrintPerson(IPerson p)
{
Contract.Requires(p != null);
...
}
void Foo()
{
var p = GetPerson(id);
PrintPerson(p); // a warning here: can not verify p != null
}
И, что совершенно не имеет отношения к вопросу, обычно это будет более эффективно, если persons — это (например) словарь:
IPerson GetPerson(Guid personId)
{
Person p = null;
this.persons.TryGetValue(personId, out p);
return p;
}
Комментарии:
1. Я просто расширил свой вопрос своим ожидаемым поведением. На самом деле мне нравится помечать метод GetPerson чем-то вроде атрибута, говорящего, что вызывающий должен иметь возможность обрабатывать возвращаемое значение null.
2. @schoet, я понял, суть в том, что вы получаете именно такой результат, ничего не делая. GetPerson() без постусловия уже говорит «Я мог бы вернуть null»
3. > Теперь он работает, я установил версию без статической проверки. Спасибо!