我应该为通用接口使用类型化代码契约吗

本文关键字:代码 契约 类型化 接口 我应该 | 更新日期: 2023-09-27 18:19:25

我有一个数学库的通用接口,如下所示:

[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. 我可以在通用接口上指定多个约定类吗?每个特定类型都有一个约定类(例如,在IMaths<T>上同时具有[ContractClass(typeof(MathsDoubleContracts))][ContractClass(typeof(MathsDecimalContracts))]属性)?这样做明智吗
  2. 如果而不是使用通用接口(例如,从IMathsDouble开始,其中所有函数都是根据doubles定义的,稍后添加IMathsDecimal),我会更好吗

我应该为通用接口使用类型化代码契约吗

Q1

你能举个例子吗。

编辑

没有。它不允许多重。参考此处。

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

AllowMultiple = false

Q2

是的,尽管泛型可能提供一些小的好处。您的界面并不是真正通用的。例如,我不能使用IMaths<File>。实际上,我在这里回答了一个不同但相关的问题。

您可以添加诸如where T : ...之类的限制,但这也不行,因为您必须仅限于intdouble,而您只能执行where T : struct,这是不一样的。在这里,泛型只是一种装饰,IMaths<T>的抽象不能按原样使用(或者它可以吗?可以取决于您的代码),您需要具体的类或接口。

子接口在这里是一个安全的选择

interface IntMaths : IMaths<int>
{
}

我通过将约定应用于通用接口来实现这一点,然后在运行时推断约定类型。

然而,我的问题是在"公共代码"程序集中定义一个基础抽象接口,该接口应用于IService类型的对象,然后为我需要的特定类型的实现继承它。

然而,我不必指定特定于类型的实现,我可以简单地(通过依赖注入)在运行时确定契约和对象类型。。。

代码契约继承

我认为我的问题是使其"可移植"