Контракты C # Code: Как проверить параметры метода интерфейса, определенного в другой сборке? - PullRequest
2 голосов
/ 13 февраля 2011

У меня есть ситуация, я не знаю, как это должно быть решено. Согласно разделу 3 руководства пользователя метод контракта, т. Е. Require или Ensure, не допускается в переопределении методов / свойств или реализаций интерфейса. Методы контракта должны быть объявлены в корневом виртуальном / абстрактном методе, и поскольку вы не можете объявить код в абстрактном методе, вам придется работать с ContractClassAttribute и ContractClassForAttribute. То же самое касается методов контракта для участников интерфейса (и их реализации).

Но что, если я хочу использовать интерфейс, который сам не создал? Например, IList<T> не реализует эти методы контракта, но я также не могу установить ContractClassAttribute. Как мне сделать проверку параметров, например, в реализации IList<T>.this[int]? Следующие решения не допускаются:

T IList<T>.this[int i]
{
    get
    {
        Contract.Requires(i >= 0);//not allowed

        if (i < 0)
            throw new ArgumentException();
        Contract.EndContractBlock();//also not allowed
        ...
    }
}

Являются ли устаревшие операторы if-then-throw без EndContractBlock единственным решением?

Ответы [ 2 ]

2 голосов
/ 13 февраля 2011

Прежде всего, IList уже указывает это предварительное условие.Я просто попробовал, чтобы убедиться: "Предварительное условие не выполнено: index> = 0" .

Более того, насколько я понимаю, условия публикации разрешены, только предварительные условия - нет.

Если вы все еще хотели бы добавить другие предварительные условия, я думаю, что это отвечает на ваш вопрос: http://social.msdn.microsoft.com/Forums/en/codecontracts/thread/af403bbc-ca4e-4546-8b7a-3fb3dba4bb4a

В основном все сводится к тому, что вы не должны этого делать, как это было быбросить вызов цели кодовых контрактов.

1 голос
/ 13 февраля 2011

Причина, по которой вы не можете добавить предварительные условия, - это та же причина, по которой вы не можете сделать это:

interface IInterface
{
    void Foo(Parent x);
}

class Implementation : IInterface
{
    void Foo(Child x);
}

Это связано с (со / против) дисперсией & mdash; Параметры метода противоречивы, то есть тип, который вы принимаете, должен быть «как минимум таким же большим / либеральным», как тип, указанный в интерфейсе.

Добавление большего количества предварительных условий делает тип меньше / более строгим, точно так же, как если бы был принят подкласс типа (как в примере выше). * Вы не можете сделать это по понятным причинам & mdash; класс, который реализует интерфейс, может не работать при передаче правильных аргументов! Если бы вы перевернули Parent & Child, все было бы в порядке.

С типами возвращаемых методов все наоборот: они ковариантны, то есть вы должны быть «хотя бы такими же маленькими / строгими», как тип, указанный в интерфейсе. Вот почему вы можете добавлять постусловия, потому что вы делаете тип «меньше / строже». По той же причине, по которой это работает:

interface IInterface
{
    Parent Foo();
}

class Implementation : IInterface
{
    Child Foo();
}

* (На самом деле возникает вопрос о том, сможете ли вы удалить предварительные условия из реализации классов. Это было бы интересной возможностью.)

...