我刚刚升级到visual studio 2010并安装了代码合同msi.当我尝试使用它时,我得到一个编译器错误,即v3.5和v4框架中都存在system.diagnostics.contracts.contract dll.有谁知道我该怎么做才能解决这个问题?谢谢.
我正在尝试使用C#中的CodeContracts看起来更像语句,所以我需要一个工具,允许我在编译器看到之前替换一些代码,如果没有办法,我猜Visual Studio插件也会有帮助.
我是Code Contracts的新手,我对如何将它与IoC集成提出了疑问.我试图在简单的测试程序(经典的consolle项目)中使用Code Contracts,但现在我想在我的官方项目中使用它.问题是:如果我有一个容器在类的构造函数方法中提供我的服务接口,我如何使用代码约定来检查传递的值?
经典场景可能是
[ContractClass(typeof(ArticoliBLLContract))]
public interfare IMyInterface
{
void method1(int a)
void method2(string b)
void method3(bool c)
}
[ContractClassFor(typeof(IArticoliBLL))]
public abstract class MyContractsClass : IMyInterface
{
public void method1(int a)
{
Contract.Requires<ArgumentOutOfRangeException>(a > 0,"a must be > 0");
}
public void method2(string b)
{
Contract.Requires<ArgumentOutOfRangeException>(!String.IsNullOrEmpty(b),"b must be not empty");
}
public void method3(bool c)
{
Contract.Requires<ArgumentOutOfRangeException>(c == true,"c must be true");
}
}
public class MyClass : IMyInterface
{
private ITFactory _factory = null;
private IMyDAL _myDAL = null; …Run Code Online (Sandbox Code Playgroud) 我想使用抽象类将代码契约添加到通用接口,但是验证了type参数.
这是我想做的一个例子:
[ContractClass(typeof(ContractsForIRepository<,>))]
public interface IRepository<T, in TId> where T : IEntity
{
T GetById(TId id);
T Persist(T entity);
void Remove(TId id);
}
[ContractClassFor(typeof(IRepository<,>))]
internal abstract class ContractsForIRepository<T, TId> : IRepository<T, TId>
{
public T GetById(TId id)
{
Contract.Requires(id != null);
return default(T);
}
public T Persist(T entity)
{
Contract.Requires(entity != null);
return default(T);
}
public void Remove(TId id)
{
Contract.Requires(id != null);
}
}
Run Code Online (Sandbox Code Playgroud)
我可以通过放弃条件轻松地让它工作:
public interface IRepository<T, in TId> where T : IEntitypublic interface IRepository<T, in TId> …代码契约一直给我"可能在空引用上调用一个方法"警告所有我的LINQ语句,我找不到一种方法来使它们静音.例如,以下方法生成两个这样的警告,因为我正在访问"car"对象的"Make"和"Model"属性,而不首先检查null.
public IEnumerable<string> GetCarModelsByMake(string make)
{
return from car in Cars
where car.Make == make
select car.Model;
}
Run Code Online (Sandbox Code Playgroud)
在我的特定情况下,我知道Cars集合永远不会包含任何空条目,所以我想我可以在方法中添加一个Assume来静音静态检查器,如下所示:
public IEnumerable<string> GetCarModelsByMake(string make)
{
Contract.Assume(Cars.All(car => car != null));
return from car in Cars
where car.Make == make
select car.Model;
}
Run Code Online (Sandbox Code Playgroud)
但这不起作用,大概是因为期望静态检查器理解它有点太多了.所以,我决定使用以下SuppressMessage属性来禁止警告:
[SuppressMessage("Microsoft.Contracts", "NonNull")]
Run Code Online (Sandbox Code Playgroud)
但由于某种原因,这无法抑制警告.我甚至尝试了以下SuppressMessage属性,其中没有一个工作:
[SuppressMessage("Microsoft.Contracts", "Requires")]
[SuppressMessage("Microsoft.Contracts", "Ensures")]
[SuppressMessage("Microsoft.Contracts", "Invariant")]
Run Code Online (Sandbox Code Playgroud)
我甚至尝试使用ContractVerification属性完全禁用该方法的合同验证:
[ContractVerification(false)]
Run Code Online (Sandbox Code Playgroud)
但这也不起作用.所以,我决定在LINQ语句的"where"子句中添加一个显式的空检查:
public IEnumerable<string> GetCarModelsByMake(string make)
{
return from car in Cars
where car != null && car.Make == make
select car.Model;
}
Run Code Online (Sandbox Code Playgroud)
这成功地消除了"where"子句的警告,但它没有消除"select"子句的警告.事实上,我发现实际上摆脱两个警告的唯一方法是向LINQ语句中的每个子句添加空检查,如下所示:
public IEnumerable<string> GetCarModelsByMake(string make) …Run Code Online (Sandbox Code Playgroud) 更新 - 由于我方缺乏解释,我改写了帖子.
您如何看待使用代码约定在无效输入上抛出异常?(我正在编写我的服务合同,要求UserName不为null或包含空格)
MembershipServiceContracts.cs - 位于子文件夹的服务层中
[ContractClassFor(typeof (IMemberShipService))]
internal abstract class MemberShipServiceContracts : IMemberShipService
{
#region IMemberShipService Members
public MembershipCreateStatus CreateUser(string userName, string password, string email)
{
Contract.Requires(!String.IsNullOrWhiteSpace(userName), "Test");
Contract.Requires(!String.IsNullOrWhiteSpace(password));
Contract.Requires(!String.IsNullOrWhiteSpace(email));
return default(MembershipCreateStatus);
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
MembershipService.cs - 位于我的服务层
[ContractClass(typeof (MemberShipServiceContracts))]
public interface IMemberShipService
{
MembershipCreateStatus CreateUser(string userName, string password, string email);
}
public class MemberShipService : IMemberShipService
{
private readonly MembershipProvider _provider;
public MemberShipService()
: this(null)
{ }
public MemberShipService(MembershipProvider provider)
{
_provider = provider ?? Membership.Provider;
} …Run Code Online (Sandbox Code Playgroud) 一旦在项目的属性中禁用运行时合同检查,就会为合同类抛出FxCop违规(假设您通过接口实现合同,然后在抽象类中定义合同).
重新启用运行时合同检查,所有违规都会消失.
这是什么原因?
违规行为:
CA1811 ObjectInvariant似乎没有上游调用者
和
CA1033使MyClassContract密封
这是没有意义的,因为合同类必须是抽象的.
我最近在我的解决方案中添加了代码合同.经过一些修改后,我们的构建运行没有任何问题,但由于代码合同,我们的单元测试失败.
环境:
Debug和Release DoNotBuild为自定义配置设置了标志BuildServer/p:CodeContractsEnableRuntimeChecking=false;CodeContractsReferenceAssembly=false构建服务器中的示例错误文本:
测试方法Web.Tests.AccountControllerTests.CreateAccount_Pass_NoPasswordSend_Test抛出异常:System.Diagnostics.Contracts.ContractException:必须使用代码契约二进制重写器(CCRewrite)重写一个程序集(可能是"Cms.Web"),因为它正在调用Contract.Requires和CONTRACTS_FULL符号已定义.从项目中删除CONTRACTS_FULL符号的任何显式定义并重建.
我已经检查了构建服务器的诊断输出,并且没有CONTRACTS_FULL可以在任何地方找到的符号.
我不想在构建服务器上启用代码合同,主要是因为我之前尝试过没有成功,并且由于时间限制我放弃了(经过更多搜索后我得出结论,这是不可能的,因为微软不允许要在构建服务器上安装的自定义扩展.我只是想忽略构建服务器上的代码契约,但单元测试执行似乎没有这样做.
任何人对我需要查看的位置有任何想法,以确保单元测试忽略代码合同?看起来这应该是可能的吗?也许我可以在构建定义中设置另一个标志,它将被单元测试选中?
编辑
请注意,构建服务器作为Microsoft服务作为Visual Studio Team Services(以前称为Visual Studio Online)的一部分在云中被HOSTED.这意味着它不是我们的构建服务器,我们无法控制构建服务器上安装的内容.即便如此,我们仍希望使用代码合同.下面接受的答案是一种允许这种情况的方法.
我有一个这样的课:
public class Article {
private Category? category;
private string content;
public Article(Category? category,string content){
Contract.Ensures(this.category == category); // error
}
}
Run Code Online (Sandbox Code Playgroud)
但在Ensure方法上会出现此错误:
运算符'=='不能应用于'类别'类型的操作数 和'类别?'
我怎么能避免这种情况?
code-contracts ×10
c# ×8
.net ×2
azure-devops ×1
constructor ×1
exception ×1
fxcop ×1
generics ×1
linq ×1
macros ×1