Должен ли я использовать контракты с типизированным кодом для универсальных интерфейсов? - PullRequest
1 голос
/ 05 января 2012

У меня есть общий интерфейс для библиотеки математики, что-то вроде этого:

[ContractClass(typeof(MathsDoubleContracts))]
public interface IMaths<T>
{
    T SomeFunction(T n);
}

Это позволяет мне создавать IMaths<double>, IMaths<decimal> и т. Д. (Хотя сначала мне нужно толькоdouble версия).

Я бы хотел заключить контракты на код.В настоящее время я сделал это:

[ContractClassFor(typeof(IMaths<double>))]
public abstract class MathsDoubleContracts : IMaths<double>
{
    public double SomeFunction(double n)
    {
        // Always positive
        Contract.Ensures(0 <= Contract.Result<double>());

        return double.NaN;
    }
}

Кажется, это работает, но я довольно удивлен, что это работает (учитывая, что я указываю контракты на IMaths<double>, а не IMaths<T>).

Меня интересует:

  1. Могу ли я указать несколько классов контрактов на универсальном интерфейсе, по одному для каждого конкретного типа, который я хочу использовать (например, иметь оба [ContractClass(typeof(MathsDoubleContracts))] и [ContractClass(typeof(MathsDecimalContracts))] атрибутов на IMaths<T>)?Разве это разумно?
  2. Было бы лучше, если бы не вообще использовали универсальные интерфейсы (т. Е. Начнем, скажем, с IMathsDouble, где все функции определены в терминахудваивается, добавляя IMathsDecimal позже)?

Ответы [ 2 ]

1 голос
/ 05 января 2012

Q1

Можете ли вы привести пример.

EDIT

Нет. Это не позволяет несколько. Ссылка здесь .

AttributeUsageAttribute(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]

Примечание AllowMultiple = false.

Q2

Да, хотя дженерики могут дать небольшую выгоду. Ваш интерфейс не является действительно общим. Я не могу использовать IMaths<File> например. Я действительно ответил на другой, но связанный вопрос здесь .

Вы можете добавить ограничения, такие как where T : ..., но это также не поможет, поскольку вам нужно ограничиться только int, double, тогда как вы можете делать только where T : struct, что не одно и то же. Здесь дженерики - просто украшение, и абстракция IMaths<T> не может использоваться как есть (или может ли это? Может зависеть от вашего кода), и вам нужны конкретные классы или интерфейсы.

Безопасным вариантом здесь является субинтерфейс

interface IntMaths : IMaths<int>
{

}
0 голосов
/ 16 февраля 2012

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

Однако моя проблема заключается в определении базового абстрактного интерфейса в сборке "общего кода"который применяется к объекту типа IService, а затем наследует его для реализаций конкретного типа, которые мне требуются.

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

Наследование контракта кода

Я думаю, что моя проблема в том, чтобы сделать его "портативным"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...