#c# #interface #code-contracts
#c# #интерфейс #код-контракты
Вопрос:
Я не могу настроить контракты кода в своем классе. Я следовал документации и примеру, но это не работает.
Я бы хотел вставить условие контрактов кода в свой интерфейс, вот мой код
Интерфейс
[ContractClass(typeof(ArticleBLLContract))]
public interface IArticleBLL
{
int getArticleNSheet(string IdBox);
IEnumerable<IArticle> getArticleValue(string IdBox, string IdLanguage);
}
Класс Contract
[ContractClassFor(typeof(IArticleBLL))]
public sealed class ArticleBLLContract : IArticleBLL
{
int IArticleBLL.getArticleNSheet(string IdBox)
{
Contract.Requires<ArgumentOutOfRangeException>(!String.IsNullOrEmpty(IdBox),"IdBox has no valid value");
return default(int);
}
IEnumerable<Base.Article.IArticle> IArticleBLL.getArticleValue(string IdBox, string IdLanguage)
{
Contract.Requires<ArgumentOutOfRangeException>(!String.IsNullOrEmpty(IdBox), "IdBox has no valid value");
Contract.Requires<ArgumentOutOfRangeException>(!String.IsNullOrEmpty(IdLanguage), "IdLanguagehas no valid value");
Contract.Ensures(Contract.Result<IEnumerable<Base.Article.IArticle>>() != null, "Return value is out of Range");
return default(IEnumerable<Base.Article.IArticle>);
}
}
Класс для применения контракта
public class ArticleBLL : IArticleBLL
{
public int getArticlNSheet(string IdBox)
{
try
{
return _Dal...
}
catch (Exception ex)
{
throw ex;
}
}
public IEnumerable<IArticle> getArticleValue(string IdBox, string IdLanguage)
{
IEnumerable<IArticle> article = null;
try
{
article = _Dal...
return article;
}
catch (Exception ex)
{
throw ex;
}
}
}
Я попытался вставить точку останова в эту строку
Contract.Requires<ArgumentOutOfRangeException>(!String.IsNullOrEmpty(IdBox),"IdBox has no valid value");
но когда я вызываю метод, он никогда не проходит здесь
Это конфигурация моего проекта
Что-то не так?
Спасибо!
Ответ №1:
Режим сборки в вашей конфигурации должен быть «Требуется стандартный контракт».
Комментарии:
1. Я прочитал, что при настройке параметра «Требуется стандартный контракт» контракты кода отсутствуют в моем выпущенном коде, но я бы вставил его также в свой выпущенный код. Должен ли я в любом случае устанавливать опцию «Требуется стандартный контракт»? Спасибо!
2. Вы можете настроить конфигурацию по-разному для отладки и выпуска. Итак, если вы хотите, чтобы проверка контракта была включена в вашу сборку выпуска, вы также должны установить для нее значение «Требуется стандартный контракт».
3. Добавить: обычно вам не нужно проверять требования в производственной среде. Если в некоторых случаях ожидается неправильный ввод, то вы должны явно обработать это в своем коде. Контракты кода предназначены для проверки предположений, которые всегда должны быть истинными. Итак, совершенно нормально иметь контракты в средах разработки, тестирования и принятия, но я бы не стал использовать их в производственной среде.
Ответ №2:
Полная переписка, основанная на комментариях до сих пор
Я создал проект библиотеки классов и поместил туда интерфейс и его класс contract. Я установил для него значение «Требуется стандартный контракт», проверки до и после выполнения и сборку ссылочной сборки контракта (я установил идентичные параметры для Debug и Release).
Затем я получил консольное приложение с классом, реализующим интерфейс, и установил «Требуется стандартный контракт», предварительные и последующие проверки во время выполнения (опять же, одинаковые между Debug и Release).
Запуская его либо в режиме отладки, либо в режиме выпуска, я получаю сообщение ArgumentOutOfRangeException
при попытке вызвать getArticleNSheet
.
За очевидным исключением переключения на «Требуется стандартный контракт», что в приведенном выше не соответствует вашей текущей настройке?
И, на самом деле, я был в ошибке ранее. С помощью «Требуется стандартный контракт» я действительно могу достичь точки останова в классе contract при отладке. Я не уверен, каким волшебством он способен это сделать — поскольку он не выполняет код в этом классе буквально — о чем свидетельствует тот факт, что вы можете переписать метод в классе contract как:
int IArticleBLL.getArticleNSheet(string IdBox)
{
Contract.Requires<ArgumentOutOfRangeException>(!String.IsNullOrEmpty(IdBox), "IdBox has no valid value");
throw new NotImplementedException();
}
Вы можете поставить точку останова в Contract.Requires
строке, и, похоже, она попадает в нее (после предупреждения о несоответствиях файлов, вероятно, из-за перезаписи). Но если предположить, что вы передали непустую строку, она не выдает NotImplementedException
.
Комментарии:
1. Я попытался передать строку. В методе getArticleNSheet пусто, но возникли какие-либо исключения. Я также пытался перейти на неявные реализации интерфейса, но у меня не возникло исключений. Что-то не так в конфигурации? Спасибо
2. @Faber — Предполагая, что все это находится в одной сборке, я также обнаружил, что контракт, похоже, не проверен. Если я изменю конфигурацию сборки ссылки на контракт на «Build» вместо «None», я затем получу предупреждения о том, что мне нужно реализовать проверку пользовательских аргументов, или, как сказал Рой, переключиться на «Требуется стандартный контракт»
3. Я пытался изменить конфигурацию, но это не работает. У меня есть интерфейс и контракты в одной сборке, но класс, который реализует интерфейс, находится в другой сборке. Какая наилучшая конфигурация для использования контрактов кода с большим количеством сборок и сохранением контрактов также в выпущенном коде? Спасибо!!
4. @Faber — Я переписал свой ответ
5. …awesome…it работает!! Я не установил ссылку на сборку контракта сборки. Спасибо!!!