Я создаю библиотеки классов, некоторые, которые используются другими во всем мире, и теперь, когда я начинаю использовать Visual Studio 2010, я задаюсь вопросом, как хорошая идея это для меня для переключения на использование контрактов кода вместо регулярных операторов "if" старого стиля.
т.е. вместо этого:
if (fileName == null)
throw new ArgumentNullException("fileName");
используйте это:
Contract.Requires(fileName != null);
Причина, которую я спрашиваю, состоит в том, что я знаю, что статическое средство проверки не доступно мне, таким образом, я немного озабочен некоторыми предположениями, что я делаю, что компилятор не может проверить. Это могло бы привести к библиотеке классов, не компилирующей для кого-то, который загружает ее, когда у них есть статическое средство проверки. Это, вместе с тем, что я не могу даже воспроизвести проблему, сделало бы ее утомительной для фиксации, и я заключу, что она не говорит красноречивее всяких слов к качеству моей библиотеки классов, если она по-видимому даже не компилирует из поля.
Таким образом, у меня есть несколько вопросов:
Любой совет приветствовался бы.
Править: Позвольте мне разъяснить то, что я имею в виду.
Скажем, у меня есть следующий метод в классе:
public void LogToFile(string fileName, string message)
{
Contracts.Requires(fileName != null);
// log to the file here
}
и затем у меня есть этот код:
public void Log(string message)
{
var targetProvider = IoC.Resolve<IFileLogTargetProvider>();
var fileName = targetProvider.GetTargetFileName();
LogToFile(fileName, message);
}
Теперь, здесь, МОК умирает, разрешает некоторый "случайный" класс, который предоставляет мне имя файла. Скажем, это для этой библиотеки, нет никакого возможного способа, которым я могу возвратить класс, который не даст мне непустое имя файла, однако, из-за природы вызова МОК, статический анализ не может проверить это и таким образом мог бы предположить, что возможное значение могло быть нулевым.
Следовательно, статический анализ мог бы прийти к заключению, что существует риск LogToFile
метод, называемый с a null
аргументу, и таким образом не удается создать.
Я понимаю, что могу добавить предположения коду, говоря, что компилятор должен взять его в качестве, учитывая, что fileName
Я возвращаюсь из того метода, никогда не будет пустым, но если бы у меня нет статического анализатора (Профессионал VS2010), вышеупомянутый код скомпилировал бы для меня, и таким образом я мог бы оставить это как ошибку сна для кого-то с Окончательным для нахождения. Другими словами, не было бы никакого времени компиляции, предупредив, что могла бы быть проблема здесь, таким образом, я мог бы выпустить библиотеку как есть.
Таким образом, действительно ли это - реальный сценарий и проблема?
Если оба метода LogToFile
и Log
являются частью вашей библиотеки, возможно, что ваш Метод Log
не будет компилироваться, как только вы включите статическую проверку. Это, конечно, также произойдет, когда вы предоставите код другим, которые компилируют ваш код с помощью статической проверки. Однако, насколько мне известно, статическая программа проверки вашего клиента не будет проверять внутреннее устройство поставляемой вами сборки. Он будет статически проверять собственный код на соответствие общедоступному API вашей сборки. Так что пока вы просто отправляете DLL, все будет в порядке.
Конечно, есть изменение в доставке библиотеки, которая имеет очень раздражающий API для пользователей, у которых действительно включена статическая проверка, поэтому я думаю, что рекомендуется поставлять вашу библиотеку только с определениями контрактов, если вы проверили удобство использования. API как со статической проверкой, так и без нее.
Обратите внимание на изменение существующих вызовов if (cond) throw ex
на вызовы Contracts.Requires (cond)
для вызовов общедоступного API, которые вы уже добавили в предыдущий выпуск. . Обратите внимание, что метод Requires
генерирует другое исключение ( RequiresViolationException
, если я правильно помню), чем то, что вы обычно вызываете ( ArgumentException
). В этой ситуации используйте перегрузку Contract.Requires . Таким образом, ваш интерфейс API останется неизменным.
Нет; статический анализатор никогда не помешает успешной компиляции (если только она не выйдет из строя!).
Статический анализатор предупредит вас о недоказанных предварительных / постусловиях, но не останавливает компиляцию.
Во-первых, статическая проверка на самом деле (насколько я понимаю) доступен только в окончательной / академической редакции - поэтому, если все в вашей организации не используют его, они могут не быть предупреждены, если они потенциально нарушают инвариант.
Во-вторых, хотя статический анализ впечатляет, он не всегда может найти все пути , которые могут привести к нарушению инварианта. Однако хорошая новость заключается в том, что контракт Requires
сохраняется во время выполнения - он обрабатывается на этапе преобразования IL - поэтому проверка существует как во время компиляции , так и время выполнения. В этом смысле он эквивалентен (но превосходит) обычной проверке if ()
.
Вы можете узнать больше о перезаписи среды выполнения, которую выполняет компиляция контракта кода здесь , вы также можете прочитать подробное руководство здесь .
РЕДАКТИРОВАТЬ: Основываясь на том, что я могу почерпнуть из руководства, я подозреваю, что описанная вами ситуация действительно возможна. Однако я думал, что это будут предупреждения, а не ошибки компиляции - и вы можете подавить их, используя System.Diagnostics.CodeAnalysis.SuppressMessage ()
. Пользователи вашего кода, у которых есть статический верификатор, также могут отмечать конкретные случаи, которые следует игнорировать, но это, безусловно, может быть неудобно, если их много.Я постараюсь найти время позже сегодня, чтобы составить окончательный тест вашего сценария (на данный момент у меня нет доступа к статическому верификатору).
Здесь есть отличный блог , который почти полностью посвящен кодовым контрактам, которые (если вы еще не видели) могут содержать интересующий вас контент.