我应该为通用接口使用类型化代码契约吗
本文关键字:代码 契约 类型化 接口 我应该 | 更新日期: 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>
上指定了合同)。
我想知道:
- 我可以在通用接口上指定多个约定类吗?每个特定类型都有一个约定类(例如,在
IMaths<T>
上同时具有[ContractClass(typeof(MathsDoubleContracts))]
和[ContractClass(typeof(MathsDecimalContracts))]
属性)?这样做明智吗 - 如果而不是使用通用接口(例如,从
IMathsDouble
开始,其中所有函数都是根据doubles定义的,稍后添加IMathsDecimal
),我会更好吗
Q1
你能举个例子吗。
编辑
没有。它不允许多重。参考此处。
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>
{
}
我通过将约定应用于通用接口来实现这一点,然后在运行时推断约定类型。
然而,我的问题是在"公共代码"程序集中定义一个基础抽象接口,该接口应用于IService类型的对象,然后为我需要的特定类型的实现继承它。
然而,我不必指定特定于类型的实现,我可以简单地(通过依赖注入)在运行时确定契约和对象类型。。。
代码契约继承
我认为我的问题是使其"可移植"