这可能主要是样式问题,但在为非void接口成员定义代码契约时,哪种方法最好:
接口:
[ContractClass(typeof(IFooContract))]
public interface IFoo
{
object Bar();
}
合同选项1:
[ContractClassFor(typeof(IFoo))]
public abstract class IFooContract : IFoo
{
object IFoo.Bar()
{
Contract.Ensures(Contract.Result<object>() != null);
throw new NotImplementedException();
}
}
合同选项2:
[ContractClassFor(typeof(IFoo))]
public abstract class IFooContract : IFoo
{
object IFoo.Bar()
{
Contract.Ensures(Contract.Result<object>() != null);
return default(T);
}
}
我见过的大多数文献倾向于选项2,但我觉得选项1更好,因为更清楚的是这纯粹是关于合同(而选项2在技术上违反了它刚刚定义的合同)。
是否存在选项2优先于选项1的情况?
答案 0 :(得分:2)
抛出异常在语义上更正确,因为无法再以一种看似合理的方式调用和使用契约类;呼叫者将被停止并告知他们的错误。
但是,NotImplementedException
似乎不是抛出的正当例外:该异常通常标记尚未实现的代码段(例如方法体)。但是已经实施了非void
合同方法 ;它只是不打算被称为。因此,我更喜欢InvalidOperationException
或NotSupportedException
。
(您甚至可以抛出自定义异常类型,例如NotMeantToBeCalledException
。)
答案 1 :(得分:1)
这应该是一个完全主观(和学术)的论点,因为永远不应该调用ContractClassFor
类中的代码。 :-)。正如您所暗示的那样(通过non-void
),exception
或default
路线只需要在课程中进行编译,并且与此处包含的合同无关。方法
显然,抽象类无法直接实例化,但是,您应该将ContractClassFor
类的可见性降低到internal
,以减少意外子类化的变化。
此外,Jon Skeet更进一步,并添加private parameterless constructor以防止任何实例化的可能性:
private IFooContract() { }
(并间接回答你的问题,进一步表达这是一个特殊的&#34;合同助手类这样一个事实,即合同无法直接放在界面中,您的代码的读者将很容易识别它,只需忽略default
/ exception
编译器安慰剂)