Действительно пытаясь любить CodeContracts в C#

Я наконец играю в догонялки со всем новым, которое было включено к.NET 3.5/4.0 Платформы. Последние несколько дней я работал с CodeContracts и я действительно очень стараюсь любить их. Мне любопытно, что другие люди думают о реализации CodeContracts в C#? А именно, как люди организуют вещи как классы Контракта для интерфейсов, методы контракта для Инвариантов Контракта и т.д.?

Мне нравится проверка, которую предоставляют контракты, на первый взгляд они выглядят великими. С несколькими простыми строками я могу получить некоторую хорошую сборку, проверяющую, прежде чем я даже выполню свой код. К сожалению, мне нелегко преобладать над чувством, что путем, которые кодируют контракты, является реализация в C#, они загромождают мой код больше, чем они документируют контракты. И в полной мере воспользоваться контрактами, я замусорил свой код предположениями и утверждаю и т.д. (который я знаю, что некоторые скажут, хорошая вещь); но поскольку некоторые мои примеры ниже покажут, это возвращает единственную простую строку к 4 или 5 строкам и действительно не добавляет достаточное значение, по-моему, по альтернативным подходам (т.е. утверждает, исключения и т.д.).

В настоящее время мои самые большие разочарования:

Интерфейсные контракты:

[ContractClass(typeof(IInterfaceContract))]
  public interface IInterface
  {
    Object Method(Object arg);
  }

  [ContractClassFor(typeof(IInterface))]
  internal abstract class IInterfaceContract
  {
    private IInterfaceContract() { }

    Object IInterface.Method(Object arg)
    {
      Contract.Requires(arg != null);
      Contract.Ensures(Contract.Result<Object>() != null);
      return default(Object);
    }
  }

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

Чрезмерное увеличение размера кода:

typeof(Action<>).MakeGenericType(typeof(Object);

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

var genericAction = typeof(Action<>);

Contract.Assume(genericAction.IsGenericType);
Contract.Assume(genericAction.GetGenericArguments().Length == 1);

genericAction.MakeGenericType(typeof(Object));

Только для хранения вещей зарегистрированными (да я знаю, что могу использовать ContractVerificationAttribute для выключения этого для метода/класса и т.д. или SuppressMessageAttribbute для предназначения для определенных сообщений но это, кажется, побеждает цель, поскольку код быстро стал бы замусоренным подавлениями и т.д.

Кроме того, беря случай как

  public class MyClass
    : IInterface
  {
    private readonly Object _obj;

    public Object Property
    {
      get
      {
        Contract.Ensures(Contract.Result<Object>() != null);
        return _obj;
      }
    }

    public MyClass(Object obj)
    {
      Contract.Requires(obj != null);

      _obj = obj;
    }
  }

obj требуется, чтобы не быть пустым, и установлен на поле только для чтения, которое не может быть изменено, все же я все еще обязан добавлять метод "разметки" к своему классу так, чтобы мое требование свойства для не возврата пустого указателя могло быть доказано:

[ContractInvariantMethod]
private void ObjectInvariant()
{
  Contract.Invariant(_obj != null);
}

Существует больше, но я полагал, что, вероятно, разглагольствовал достаточно, и я был бы очень признателен за понимание людей, намного более умных, чем я, чтобы помочь мне "как" Контракты Кода и заставить это чувство помехи кода уйти. Любое понимание о том, как лучше структурировать код, обходное решение wonkiness проблемы и т.д., значительно ценилось бы.

Спасибо!

59
задан James Wiseman 8 November 2012 в 09:51
поделиться

5 ответов

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

Команда CC заявила, что использование атрибутов недостаточно мощно, потому что в них нельзя включать такие вещи, как лямбды. Они могут включать такие вещи, как [NotNull] , но решили этого не делать , потому что они пытаются сохранить CC как можно более общими.

Одна из причин того, что CC является библиотекой (а не частью расширенного C #), заключается в том, что она поддерживается на всех языках .NET.

Подробнее о рассуждениях команды можно прочитать здесь .

Что касается фактического использования этого, до сих пор я просто хранил свои интерфейсные контракты в том же файле, что и интерфейс, что означает, что все это задокументировано в одном месте. Это то, что следует улучшить:)

Раздувание кода [...]

Ваша вторая жалоба, вероятно, может быть реализована - я бы посоветовал опубликовать ее на форуме контрактов кода . (РЕДАКТИРОВАТЬ: Кажется, у кого-то уже есть , но пока нет ответов.)

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

Кроме того, рассмотрим случай, подобный [...]

Этот был рассмотрен . Если у вас есть автоматическое свойство, вам просто нужно добавить ненулевой инвариант, и будут сгенерированы предварительные / постусловия:

public class MyClass : IInterface
{
    private Object Property { get; set; }

    [ContractInvariantMethod]
    private void Invariants()
    {
        Contract.Invariant(Property != null);
    }
}

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

26
ответ дан 24 November 2019 в 18:33
поделиться

Да, контракты загромождают все, но я чувствую, что это того стоит, когда PEX читает контракты кода и генерирует для меня 25 модульных тестов и 100% покрытие кода. Если вы еще не используете PEX, то вы упускаете самое большое преимущество кодовых контрактов. Вот начальное руководство по использованию PEX с контрактами.

12
ответ дан 24 November 2019 в 18:33
поделиться

Если вас беспокоит разрастание кода, то я бы посоветовал вам рассмотреть Аспектно-ориентированное программирование в качестве альтернативы.

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

К сожалению, поддержка AOP в C# не очень велика, но есть несколько библиотек, которые добавляют эту функциональность.

И поскольку у меня такое же чувство к другим реализациям C#, как у вас к Contracts, то сначала все кажется прекрасным, пока вы не поднимите капюшон и не начнете использовать его всерьез.

3
ответ дан 24 November 2019 в 18:33
поделиться

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

Почему вы обязаны добавлять инвариант объекта? От вас требуется добавить столько, сколько вы считаете нужным.

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

2
ответ дан 24 November 2019 в 18:33
поделиться

Я создал плагин для Visual Studio 2010, который может сэкономить вам время на создании кодовых контрактов для интерфейсов и абстрактных классов: http://visualstudiogallery.msdn.microsoft.com/en-us/d491911d-97f3-4cf6-87b0-6a2882120acf

3
ответ дан 24 November 2019 в 18:33
поделиться
Другие вопросы по тегам:

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