如何使用代码契约定义外部状态的前提条件?

时间:2012-03-06 14:32:50

标签: c# .net code-contracts specifications spec#

如何在以下界面中的Invoke方法上放置前提条件,说明ObjectId表示的对象必须存在?:

interface IDeleteObjectCommand {
   Guid ObjectId { get; }
   void Invoke();
}

尝试#1

我已经有一个名为IObjectExistsCommand的命令,可用于确定对象是否存在。这些命令可以通过IObjectExistsCommandFactory实例化。我已经考虑过执行以下操作,但这会给命令的界面(IMO)增加不良噪音:

interface IDeleteObjectCommand {
   IObjectExistsCommandFactory ObjectExistsCommandFactory { get; }
   Guid ObjectId { get; }

   // Contract.Requires(ObjectExistsCommandFactory.Create(ObjectId).Invoke());
   void Invoke();
}

尝试#2

与上述类似,但使用ServiceLocator除外。由于显而易见的原因而不受欢迎,但更清洁:

interface IDeleteObjectCommand {
   Guid ObjectId { get; }

   // Contract.Requires(ServiceLocator.Get<ObjectExistsCommandFactory>().Create(ObjectId).Invoke());
   void Invoke();
}

编辑:同样,您如何定义外部状态的后置条件?即说这种方法会导致存在新文件。

2 个答案:

答案 0 :(得分:1)

我认为这是一个坏主意。这是受竞争条件限制的合同之一,我不喜欢这些(两个来电者确认合同满足,然后一个人赢得比赛以删除对象,然后第二个获得合同违规例外它试图删除对象。)

如果要删除的对象不存在,则抛出异常。

答案 1 :(得分:0)

我决定创建一个'Preconditions'enum来定义外在的前提条件。然后我在接口上定义了一个返回enum的单独方法,从而暗示外部状态的哪些位无效:

interface IDeleteObjectCommand {
   Guid ObjectId { get; }
   DeleteObjectPreconditions? GetImpediments();

   // Contract.Requires(!this.GetImpediments().HasValue);
   void Invoke();
}

enum DeleteObjectPreconditions { ObjectExists, ObjectUnlocked };

我这样做完全疯了吗?当然,唯一的缺点是用户没有可靠的手段来满足前提条件......

编辑:我实际上更喜欢这种服务定位方法。至少通过这种方法,用户能够证明通过签约(尽管是服务定位)界面满足前提条件。

编辑2:这提出了一个有趣的问题......你如何定义外在状态的后置条件?