Почему контракты кода можно добавлять и удалять для постусловий и инвариантов объектов, но не для предусловий в C#? - PullRequest
0 голосов
/ 20 февраля 2020

Почему кодовые контракты можно добавлять и удалять для постусловий и инвариантов объектов, но не для предусловий в C#?

В книге CLR через C# я встретил следующее выдержка:

И поскольку контракт с новыми версиями не может быть ужесточен (без нарушения совместимости), вы должны тщательно рассмотреть предварительные условия при введении нового виртуального, абстрактного или интерфейсного члена. Для постусловий и инвариантов объектов контракты могут добавляться и удаляться по желанию, поскольку условия, выраженные в виртуальном / абстрактном / интерфейсном элементе, и условия, выраженные в переопределяющем элементе, просто логически объединены и объединены .

Меня очень смущает, что постусловия и инварианты объектов, контракты могут быть добавлены и удалены по желанию . Я ожидал бы предположение, что постусловия и инварианты объектов могут стать только более строгими, чем предварительные условия. Почему я ожидаю этого? Потому что я могу привести пример, когда предложение оказывается неверным. Например,

Сначала у нас было постусловие, и все работало просто отлично:

using System.Diagnostics.Contracts;

public sealed class Program
{
    public static void FooBaseContract(int i) 
    {
        Contract.Ensures(i > 0);
    }
}

public class FooBase 
{
    public virtual int i 
    {
        get {return 2;} 
    }
}
public class FooDerived : FooBase
{
    public override int i 
    {
        get {return 4;} 
    }
}

Теперь мы решили сделать постусловие более строгим:

using System.Diagnostics.Contracts;

public sealed class Program
{
    public static void FooBaseContract(int i) 
    {
        Contract.Ensures(i > 4);
    }
}

public class FooBase 
{
    public virtual int i 
    {
        get {return 2;} 
    }
}
public class FooDerived : FooBase
{
    public override int i 
    {
        get {return 4;} 
    }
}

Это определенно делает код, который работал с предыдущим постусловием, несовместимым с новым постусловием. Это означает, что мы теряем обратную совместимость, делая постусловия более строгими.

Кроме того, я не понимаю, почему автор ссылается только на virtual, abstract, or interface member. Потому что в надуманном примере, который я привел выше, несовместимость с новой версией контрактного кода произойдет, даже если я изменю код на следующий (удалите все virtual, abstract, or interface member):

using System.Diagnostics.Contracts;

public sealed class Program
{
    public static void FooBaseContract(int i) 
    {
        Contract.Ensures(i > 4);
    }
}

public class FooBase 
{
    public int i 
    {
        get {return 2;} 
    }
}

Итак, кто-то может объяснить в безошибочный способ, что мне здесь не хватает, пожалуйста?

ОБНОВЛЕНИЕ

Как уже упоминалось в разделе комментариев - кодовые контракты являются устаревшей концепцией. Это нормально для меня, я просто хотел бы понять идею - в этом случае именно поэтому мы можем сделать постусловия и объектные инварианты более строгими? Это противоречит моему здравому смыслу, означающему, что что-то было разрешено вернуть ранее (или иметь место для объектных инвариантов), и теперь мы заявляем, что что-то больше не разрешено, и автор книги говорит, что такой случай не нарушает обратная совместимость.

1 Ответ

1 голос
/ 21 февраля 2020

В тексте говорится, что условия «объединены». Это означает, что у вас просто нет возможности удалять постусловия и инварианты. Вы можете добавлять их только независимо от того, как вы пишете код.

Постусловия и инварианты - это то, что должно быть гарантировано при выходе. Имеет смысл уметь добавлять обязательства. Если вы добавляете противоречие, то CC должно пометить это как нарушение постусловия.

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

...