Как правильно применять Contract.Require в реализации интерфейсного метода?

Есть интерфейс
public interface IClassA
{
    void Method1(int value);
}


Есть класс, в котором нужно контролировать валидность входного параметра
public class ClassA: IClassA
{
    public void Method1(int value)
    {
        Contract.Requires(value > 5);
    }
}


Подобный код, выдает warning: "Method 'ClassA.Method1' implements interface method 'IClassA.Method1', thus cannot add Requires".

Что примерно понятно. Для удаление этого предупреждения нужно модифицировать код.
1. Добавить абстрактный класс, реализующий интерфейс IClassA, в котором буду содержаться проверки контрактов
2. Пометить соответствующими атрибутами интерфейс и абстрактный класс
[ContractClass(typeof(ClassAContract))]
public interface IClassA
{
    void Method1(int value);
}
[ContractClassFor(typeof(IClassA))]
public abstract class ClassAContract : IClassA
{
    public void Method1(int value)
    {
        Contract.Requires(value > 5);
    }
}


Вопросы:
1. При таком подходе, для каждого интерфейса нужно "городить" абстрактный класс. Трудоемко. Может есть способ проще, атрибуты какие-либо?
2. Если в интерфейсе объявлены события, то в абстрактном классе приходится писать "дурной код" использования неиспользуемых событий, для исключения warning-ов (The event is never used). Возможно есть более удобный способ?
  • Вопрос задан
  • 2452 просмотра
Пригласить эксперта
Ответы на вопрос 2
В книге Джозефа Албахари и Бена Албахари «C# 5.0. Справочник. Полное описание языка» глава про контракты кода там очень интересная, советую. Вот, например:

Контракты на интерфейсах
и абстрактных методах


Мощной возможностью контрактов кода является добавление условий к членам интерфейса и абстрактным методам. Двоичное средство перезаписи автоматически привязывает эти условия к конкретным реализациям членов. Специальный механизм позволяет указывать отдельный класс контракта для интерфейсов и абстрактных методов, поэтому можно написать тела методов для хранения условий контрактов. Ниже показано, как это работает:


[ContractClass (typeof (ContractForITest))] 
interface ITest 
{ 
    int Process (string s); 
}

[ContractClassFor (typeof (ITest))] 
sealed class ContractForITest : ITest 
{  
    int ITest.Process (string s) // должна использоваться явная реализация. 
    { 
        Contract.Requires (s != null); 
        return 0; // Фиктивное значение, чтобы удовлетворить компилятор. 
    } 
}


Обратите внимание, что для удовлетворения компилятора мы должны вернуть значение при реализации метода ITest.Process. Однако код, возвращающий 0, выполняться не будет. Вместо этого двоичное средство перезаписи извлекает из метода только условия и связывает их с реальными реализациями ITest.Process. Это значит, что экземпляры класса контракта никогда в действительности создаваться не будут (и любые конструкторы, которые вы напишете, также выполняться не будут). Внутри блока контракта можно реализовать присваивание временной переменной, чтобы проще было ссылаться на другие методы интерфейса. Например, если в интерфейсе ITest также определено свойство Message типа string, в ITest.Process можно было бы написать следующий код:


int ITest.Process (string s) 
{ 
    ITest test = this;
    Contract.Requires (s != test.Message);
    ...
}


Это проще, чем:

Contract. Requires (s != ((ITest)this).Message);

(Простое использование this Message работать не будет, т.к. свойство Message должно быть реализовано явно.) Процесс определения классов контрактов для абстрактных классов выглядит точно так же за исключением того, что класс контракта должен быть помечен как abstract вместо sealed.
Ответ написан
Комментировать
Neuroware
@Neuroware
Программист в свободное от работы время
что планировалось реализовать с использованием подобных интерфейсов? Есть подозрение, что использование контрактов в контексте задачи нецелесообразно.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы