Как добавить реализацию к контракту кода интерфейса при наследовании от интерфейса - PullRequest
4 голосов
/ 10 мая 2011

Мой пример - ситуация, когда интерфейсам, которые наследуют базовый интерфейс, необходимо добавить условия публикации, являющиеся результатом их дополнительных полей - пример произошел, когда я решил использовать интерфейс IInitialise в качестве интерфейсов, которые наследуются от этого неизменно желаемого условие pre / post добавлено в метод Initialize.

Я вижу, что проблема в том, что абстрактные реализации не имеют возможности избегать друг друга (из-за перехвата или переписывания).

    [ContractClass(typeof(IInitialiseContract))]
    public   interface IInitialise
    {
        bool IsInitialised { get; }
        void Initialise();

    }

    [ContractClassFor(typeof(IInitialise))]
    public abstract class IInitialiseContract : IInitialise
    {

        public bool IsInitialised
        {
            get { return default(bool); }
        }

        public void Initialise()
        {
            Contract.Ensures(IsInitialised == true);
        }
    }

потом я получаю следующий интерфейс

  [ContractClass(typeof(IEnginecontract))]
    public interface IEngine : IInitialise 
    {
        ICommandManager CommandManager { get; }
        IDictionary<int, IEntity> World { get; } 
    }

    [ContractClassFor(typeof(IEngine))]
    public abstract class IEnginecontract : IEngine
    {

        public ICommandManager CommandManager
        {
            get
            {
                Contract.Ensures(Contract.Result<ICommandManager>() != null);
                return default(ICommandManager);
            }
        }

        public IDictionary<int, IEntity> World
        {
            get
            {
                Contract.Ensures(Contract.Result<IDictionary<int, IEntity>>() != null);
                return default(IDictionary<int, IEntity>);
            }
        }

        public bool IsInitialised
        {
            get { return default(bool); }
        }

        public void Initialise()
        {
            // I would like to put my pre and post conditions here but 
            // cannot because it is implemented in the base interfaces contract.
        }
    }

Я попал сюда и не могу найти хороший, чистый способ добавить условия в Initialise ().

Edit2: Если бы я добавил в этот метод require, я бы получил ошибку, подобную этой

Предупреждение 1 Класс контракта IEngine не может определить контракт для метода IInitialise.Initialise, поскольку его первоначальное определение не относится к типу IEngine. Вместо этого определите контракт для типа IInitialise. IEngine .cs

Есть идеи?

Ответы [ 2 ]

3 голосов
/ 12 мая 2011

Любые методы из интерфейса, отличного от того, для которого вы пишете контракты, должны быть помечены abstract. Контракты для этих методов будут наследоваться автоматически, и вы не сможете их изменить (или это изменит смысл базового интерфейса, что не имеет смысла).

Итак, у вас должен быть базовый интерфейс и контракты:

[ContractClass(typeof(IInitialiseContract))]
public interface IInitialise
{
    bool IsInitialised { get; }
    void Initialise();

}

[ContractClassFor(typeof(IInitialise))]
public abstract class IInitialiseContract : IInitialise
{

    public bool IsInitialised
    {
        get { return default(bool); }
    }

    public void Initialise()
    {
        Contract.Ensures(IsInitialised == true);
    }
}

И ваш производный интерфейс и его контракты (обратите внимание на абстрактные унаследованные):

[ContractClass(typeof(IEnginecontract))]
public interface IEngine : IInitialise 
{
    ICommandManager CommandManager { get; }
    IDictionary<int, IEntity> World { get; } 
}

[ContractClassFor(typeof(IEngine))]
public abstract class IEnginecontract : IEngine
{

    public ICommandManager CommandManager
    {
        get
        {
            Contract.Ensures(Contract.Result<ICommandManager>() != null);
            return default(ICommandManager);
        }
    }

    public IDictionary<int, IEntity> World
    {
        get
        {
            Contract.Ensures(Contract.Result<IDictionary<int, IEntity>>() != null);
            return default(IDictionary<int, IEntity>);
        }
    }

    public abstract bool IsInitialised {get;}
    public abstract void Initialise();
}
2 голосов
/ 11 мая 2011

Я не думаю, что это возможно. Я широко использую контракты кода и насколько я могу судить - я помню, что сам попробовал что-то подобное - контракт кода вашего производного интерфейса должен снова включать все условия, он не может их наследовать.

...