Подтвердить что ты не робот

"Дизайн по контракту" в С#

Я хотел попробовать небольшой дизайн по контракту в своем последнем приложении С# и хотел иметь синтаксис, похожий на:

public string Foo()
{
    set {
        Assert.IsNotNull(value);
        Assert.IsTrue(value.Contains("bar"));
        _foo = value;
    }
}

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

4b9b3361

Ответ 1

Контракты с кодом С# 4.0

Microsoft выпустила библиотеку для разработки по контракту в версии 4.0.net framework. Одной из самых крутых функций этой библиотеки является то, что она также поставляется со статическими инструментами анализа (аналогично FxCop, я думаю), которая использует детали контрактов, которые вы размещаете в коде.

Вот некоторые ресурсы Microsoft:

Вот некоторые другие ресурсы:

Ответ 2

SpeС# - популярный проект исследования Microsoft, который допускает некоторые конструкции DBC, такие как проверка сообщений и предварительных условий. Например, двоичный поиск может быть реализован с условием pre и post вместе с инвариантами цикла. Этот пример и многое другое:

 public static int BinarySearch(int[]! a, int key)
    requires forall{int i in (0: a.Length), int j in (i: a.Length); a[i] <= a[j]};
    ensures 0 <= result ==> a[result] == key;
    ensures result < 0 ==> forall{int i in (0: a.Length); a[i] != key};
 {
   int low = 0;
   int high = a.Length - 1;

   while (low <= high)
     invariant high+1 <= a.Length;
     invariant forall{int i in (0: low); a[i] != key};
     invariant forall{int i in (high+1: a.Length); a[i] != key};
   {
     int mid = (low + high) / 2;
     int midVal = a[mid];

     if (midVal < key) {
       low = mid + 1;
     } else if (key < midVal) {
       high = mid - 1;
     } else {
       return mid; // key found
     }
   }
   return -(low + 1);  // key not found.
 }

Обратите внимание, что использование языка SpeС# дает возможность проверять время компиляции для конструкций DBC, что для меня - лучший способ использовать DBC. Часто, полагаясь на утверждения времени исполнения, становится головной болью в производстве, и люди обычно предпочитают использовать исключения.

Есть другие языки, которые включают концепции DBC в качестве конструкций первого класса, а именно Eiffel, который также доступен для платформы .NET.

Ответ 3

Помимо использования внешней библиотеки, у вас есть простое утверждение в System.Diagnostics:

using System.Diagnostics

Debug.Assert(value != null);
Debug.Assert(value == true);

Не очень полезно, я знаю.

Ответ 6

Оглядываясь на код для Moq, я увидел, что они используют класс под названием Guard, который предоставляет статические методы для проверки условий pre и post, Я думал, что это было аккуратно и очень ясно. В нем выражается то, о чем я бы подумал при реализации дизайна по контракту в моем коде.

например.

public void Foo(Bar param)
{
   Guard.ArgumentNotNull(param);
} 

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

Ответ 7

Вы можете использовать реализацию Design By Contract от четкой архитектуры. Вот ссылка: http://code.google.com/p/sharp-architecture/

Привет,

Лян

Ответ 9

Вы можете проверить nVentive Umbrella:

using System;
using nVentive.Umbrella.Validation;
using nVentive.Umbrella.Extensions;

namespace Namespace
{
    public static class StringValidationExtensionPoint
    {
        public static string Contains(this ValidationExtensionPoint<string> vep, string value)
        {
            if (vep.ExtendedValue.IndexOf(value, StringComparison.InvariantCultureIgnoreCase) == -1)
                throw new ArgumentException(String.Format("Must contain '{0}'.", value));

            return vep.ExtendedValue;
        }
    }

    class Class
    {
        private string _foo;
        public string Foo
        {
            set
            {
                _foo = value.Validation()
                    .NotNull("Foo")
                    .Validation()
                    .Contains("bar");
            }
        }
    }
}

Я хочу, чтобы расширения Validation были сборщиками, поэтому вы могли бы сделать _foo = value.Validation().NotNull("Foo").Contains("bar").Value;, но это то, что есть (к счастью, его открытый источник, поэтому создание его строителя - это тривиальное изменение).

И в качестве альтернативного решения вы можете рассмотреть проверку домена.

Наконец, новые языки M, как часть Осло, поддерживают ограничения на их экстенты и поля, которые переводят как на проверку T-SQL, так и на класс CLR с функционирующими проверками валидации (хотя Осло долгое время отходит от выпуска).

Ответ 10

Для моего текущего проекта (февраль 2010, VS 2008) я выбрал http://lightcontracts.codeplex.com/

Простая, это просто проверка времени выполнения, без какой-либо странной сложности, вам не нужно выводить из некоторых "странных" базовых классов, без интеграции AOP, VS, которые не будут работать на некоторых рабочих станциях разработчиков и т.д.

Простота по сложности.

Ответ 11

Самый простой способ и способ, используемый в самой .NET Framework, - это сделать:

public string Foo()
{
    set {
        if (value == null)
            throw new ArgumentNullException("value");
        if (!value.Contains("bar"))
            throw new ArgumentException(@"value should contain ""bar""", "value");

        _foo = value;
    }
}