Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用代码契约定义外部状态的前提条件?_C#_.net_Code Contracts_Specifications_Spec# - Fatal编程技术网

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

C# 如何使用代码契约定义外部状态的前提条件?,c#,.net,code-contracts,specifications,spec#,C#,.net,Code Contracts,Specifications,Spec#,如何在以下接口中的Invoke方法上放置一个先决条件,说明由ObjectId表示的对象必须存在: interface IDeleteObjectCommand { Guid ObjectId { get; } void Invoke(); } 尝试#1 我已经有一个名为iobjectexistscomand的命令,可以用来确定对象是否存在。这些命令可以通过IObjectExistsCommandFactory实例化。我曾考虑过执行以下操作,但这会给命令的界面(IMO)增加不必要的干

如何在以下接口中的
Invoke
方法上放置一个先决条件,说明由
ObjectId
表示的对象必须存在:

interface IDeleteObjectCommand {
   Guid ObjectId { get; }
   void Invoke();
}
尝试#1

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

尝试#2

与上述类似,除了使用
ServiceLocator
。由于明显的原因不可取,但更干净:

interface IDeleteObjectCommand {
   Guid ObjectId { get; }

   // Contract.Requires(ServiceLocator.Get<ObjectExistsCommandFactory>().Create(ObjectId).Invoke());
   void Invoke();
}
接口IDeleteObjectCommand{
Guid对象ID{get;}
//Contract.Requires(ServiceLocator.Get().Create(ObjectId.Invoke());
void Invoke();
}

编辑:类似地,如何定义外部状态的post条件?也就是说,这种方法会导致一个新文件的存在。

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

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

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

enum DeleteObjectPreconditions { ObjectExists, ObjectUnlocked };

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

编辑:实际上,我更喜欢服务定位方法,而不是此方法。至少通过这种方法,用户能够证明通过合同(尽管服务位于)接口满足了先决条件


编辑2:这提出了一个有趣的问题。。。如何定义外部状态的post条件?

我认为这是个坏主意。这是受竞争条件约束的合同之一,我不喜欢(两个调用方验证合同是否满足,然后一个赢得删除对象的竞争,然后第二个在尝试删除对象时获得合同冲突异常)


如果要删除的对象不存在,则引发异常

向接口添加一个
Object对象{get;}
属性,该属性返回对象本身而不是ID?有趣的问题。除了提供通过接口本身进行检查的方法(尝试#1)或提供静态方法(尝试#2),我看不出还有其他选择。但我可能错了。嗯,我不确定预先加载实体在所有情况下都是可行的折衷方案。不过,谢谢你的建议。这看起来更像是一种主张,而不是合同检查。我认为契约检查将涵盖ObjectId不是Guid.Empty,这使您有信心继续。这里的问题是,即使用户遵守方法上的所有先决条件,也可能收到异常。我认为这样做的目的是使方法具有确定性,这样用户就可以100%确定,当他们遵守前提条件时不会抛出异常。“当然,唯一的缺点是,用户没有可证明的手段来永远满足前提条件…”所以唯一的缺点是它毫无意义?这对我来说似乎是一个“唯一”的缺点。我想这是一个由绝望带来的短暂的疯狂时刻。我并不是真的同意这个解决方案:)如果你不能百分之百地满足合同,那么它们就不应该是合同。:)既然外在状态可以在任何时候被其他人修改,这是否意味着我们应该避免在这些事情上设置前置/后置条件?例如,“方法X的一个先决条件是文件必须存在”。我同意你的说法,但这是否与你不应该依赖异常来控制应用程序流的概念相矛盾?此外,调用者是否有责任通过TransactionScope或其他机制确保资源上存在锁?我认为这正是异常的原因。这里还有另一个更明显的例子:假设一个函数
需要(File.Exists(someArg))
-调用者绝对没有办法保证这一点,因为它依赖于第三方状态,无法控制,所以最好在失败时抛出异常,而不是
需要
interface IDeleteObjectCommand {
   Guid ObjectId { get; }
   DeleteObjectPreconditions? GetImpediments();

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

enum DeleteObjectPreconditions { ObjectExists, ObjectUnlocked };