как настроить контракты кода в интерфейсе

#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 работает!! Я не установил ссылку на сборку контракта сборки. Спасибо!!!