我最近与同事讨论过是否应该允许将null或空集合作为方法参数传递.我的感觉是,这会导致异常,因为它会破坏方法的"契约",即使它不一定会破坏方法的执行.这也具有"快速失败"的优点.我的同事辩称,这会导致代码乱丢"非空/非空"检查,即使它不重要.
我可以看到他的观点,但允许空或空参数让我感到不安.它可以通过延迟失败来隐藏问题的真正原因!
我们来看两个具体的例子:
1)鉴于我们有一个带有重叠(Interval)方法的Interval类,如果将null作为参数传递会发生什么?我的感觉是我们应该抛出一个IllegalArgumentException来让调用者知道某些东西可能是错误的,但我的同事觉得返回false是足够的,就像在他使用它的场景中一样,如果第二个Interval是是否为空(重要的是它们是否重叠).
2)给定一个像fetchByIds(Collection ids)这样的方法,如果提供一个空集合会发生什么?再一次,我想警告打电话者发生了异常情况,但我的同事只是收到一个空列表就好了,因为他再一次并不关心是否有任何ids.
被叫代码的责任在哪里结束?在这两种情况下,调用代码都不介意参数是null还是空,但在其他情况下,这可能指向可能的错误.一个方法是否只保证只要遵守先决条件就不会破坏,或者它是否应该尝试识别潜在的错误调用?
编辑:我看到了很多很好的答案,大多数人倾向于将其定义为合同/在文档中,并坚持使用它,但我希望你的意见何时允许它,何时不允许(如果有的话).在具体的例子中,你会做什么?鉴于90%的用途,没有验证输入将是正常的,你仍然会验证清除剩余的10%中的错误,或者你宁愿解决那些出现的问题,并避免不必要的空/空检查?
我正在使用C#4.0和Code Contracts,我有自己的自定义GameRoomCollection : IEnumerable<GameRoom>.
我想确保,任何实例GameRoomCollection都不会包含null值元素.不过,我似乎无法做到这一点.我试图做一个简单明了的例子,而不是制定一般规则.这AllGameRooms是一个实例GameRoomCollection.
private void SetupListeners(GameRoom newGameRoom) {
Contract.Requires(newGameRoom != null);
//...
}
private void SetupListeners(Model model) {
Contract.Requires(model != null);
Contract.Requires(model.AllGameRooms != null);
Contract.Assume(Contract.ForAll(model.AllGameRooms, g => g != null));
foreach (GameRoom gameRoom in model.AllGameRooms)
SetupListeners(gameRoom);//<= Warning: Code Contracts: Requires unproven: newGameRoom != null
}
Run Code Online (Sandbox Code Playgroud)
任何人都可以看到,为什么我没有证明,那gameRoom不是null吗?
编辑:
在迭代之前添加对象的引用也不起作用:
IEnumerable<IGameRoom> gameRooms = model.AllGameRooms;
Contract.Assume(Contract.ForAll(gameRooms, g => g != null));
foreach (IGameRoom gameRoom in gameRooms)
SetupListeners(gameRoom);//<= …Run Code Online (Sandbox Code Playgroud) 我可以使用代码约定来定义接口上的只读,不变属性吗?即实例化后总是产生相同值的属性?
考虑以下"安全"计划:
internal class Safe
{
public static void SafeMethodWillNeverThrow()
{
try
{
var something = ThrowsNewException();
Func<int, string> x = p => something.ToString();
}
catch (Exception)
{
}
}
private static object ThrowsNewException()
{
throw new Exception();
}
public static void Main()
{
SafeMethodWillNeverThrow();
}
}
Run Code Online (Sandbox Code Playgroud)
它永远不会以异常完成.但是为什么它在我运行时失败了?为什么SafeMethodWillNeverThrow()会抛出异常?
在测试此代码之前,请阅读以下答案.
晚上好,
我刚开始玩Microsoft.Contracts(最新版本)并将其插入到示例界面之上,现在它看起来像这样:
namespace iRMA2.Core.Interfaces
{
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics.Contracts;
/// <summary>
/// Base Interface declarations for iRMA2 Extensions
/// </summary>
[InheritedExport]
[ContractClass(typeof(IiRMA2ExtensionContract))]
public interface IiRMA2Extension
{
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name of the Extension.</value>
string Name { get; }
/// <summary>
/// Gets the description.
/// </summary>
/// <value>The description.</value>
string Description { get; }
/// <summary>
/// Gets the author of the extension. Please provide complete information to get …Run Code Online (Sandbox Code Playgroud) 我打算使用新的.NET 4 Code Contracts功能进行未来的开发.这让我想知道我们是否必须Contract.Requires(...)在一系列方法中冗余地指定等效语句.
我认为一个代码示例胜过千言万语:
public bool CrushGodzilla(string weapon, int velocity)
{
Contract.Requires(weapon != null);
// long code
return false;
}
public bool CrushGodzilla(string weapon)
{
Contract.Requires(weapon != null); // specify contract requirement here
// as well???
return this.CrushGodzilla(weapon, int.MaxValue);
}
Run Code Online (Sandbox Code Playgroud)
对于运行时检查它并不重要,因为我们最终总是会遇到需求检查,如果失败我们会收到错误.
但是,当我们再次在第二次超载中没有指定合同要求时,它被认为是不好的做法吗?
此外,还将具有编译时检查的功能,并且还可能设计代码合同的时间检查.在Visual Studio 2010中,它似乎尚不适用于C#,但我认为有一些类似Spec#的语言已经可以使用.当我们编写代码来调用这样的方法时,这些引擎可能会给我们提示,而我们的参数目前可以或将会是null.
所以我想知道这些引擎是否总是会分析一个调用堆栈,直到找到一个目前不满意的合同方法?
此外,在这里我了解到的区别Contract.Requires(...)和Contract.Assume(...).我想在这个问题的背景下还要考虑差异呢?
我刚刚开始了解VS2010标配的代码契约库.我正在遇到的一件事是一些合同条款的真正含义.
例如,这两个陈述有何不同?
Contract.Requires(!mycollection.Any(a => a.ID == newID));
Contract.Requires(!Contract.Exists(mycollection, a => a.ID == newID));
Run Code Online (Sandbox Code Playgroud)
换句话说,Contract.Exists在实际应用中做了什么,对于使用我的函数的开发人员,还是对于静态代码分析系统?
我是REST的新手,听起来应该很简单.在.NET应用程序中,我可以创建对WCF服务的引用,并为我生成所有可用类型的合同.
现在我正在尝试在Windows Phone 7应用程序中使用REST服务.虽然我可以进行调用并获得正确的响应,但是有一种简单的方法来创建每个对象将被反序列化的类吗?
我正在使用RestSharp来管理我的呼叫.在我看到的一些例子中,用户已经创建了自己的类,并手动生成了xml.如果可能的话,我想避免这种情况.
非常感谢!
我可以为非泛型接口设置嵌套合同类型:
[ContractClass(typeof(Foo.FooContracts))]
public interface IFoo
{
string Bar(object obj);
}
Run Code Online (Sandbox Code Playgroud)
但是当我尝试使用通用接口做同样的事情时,它会抱怨:
[ContractClass(typeof(Foo.FooContracts<>))]
public interface IFoo<T>
{
string Bar(T obj);
}
Run Code Online (Sandbox Code Playgroud)
警告是:
合同类
Foo+FooContracts`1和类型IFoo`1必须具有相同的声明类型(如果有).
如果我FooContracts离开Foo课堂,它会在没有警告的情况下编译.
我正在用C#编写ReSharper 8.0和VS2012 for .Net 4.0.
ReSharper包含一个属性:JetBrains.Annotations.PureAttribute.这用于提供检查"不使用纯方法的返回值".
代码约定包括一个属性:System.Diagnostics.Contracts.PureAttribute.代码合同检查使用它来确保调用不会产生可见的状态更改,因此不需要重新检查对象的状态.
目前,为了获得这两种工具的功能,需要使用每个属性的方法对方法进行注释.更糟糕的是,因为它们都共享相同的类型名称,所以您需要限定每个属性.
[Pure]
[Jetbrains.Annotations.Pure]
public bool isFinished() {
...
Run Code Online (Sandbox Code Playgroud)
为避免这种情况,应该有三种方法:
这些都有可能吗?
code-contracts ×10
c# ×7
.net ×4
.net-4.0 ×1
enumerable ×1
exception ×1
forall ×1
generics ×1
interface ×1
null ×1
parameters ×1
resharper ×1
rest ×1