Почему кодовые контракты можно добавлять и удалять для постусловий и инвариантов объектов, но не для предусловий в 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;}
}
}
Итак, кто-то может объяснить в безошибочный способ, что мне здесь не хватает, пожалуйста?
ОБНОВЛЕНИЕ
Как уже упоминалось в разделе комментариев - кодовые контракты являются устаревшей концепцией. Это нормально для меня, я просто хотел бы понять идею - в этом случае именно поэтому мы можем сделать постусловия и объектные инварианты более строгими? Это противоречит моему здравому смыслу, означающему, что что-то было разрешено вернуть ранее (или иметь место для объектных инвариантов), и теперь мы заявляем, что что-то больше не разрешено, и автор книги говорит, что такой случай не нарушает обратная совместимость.