Visual studio 2010 在VisualStudio2010 Professional中为类库使用代码契约(即无静态检查)有多好?
我创建了一些类库,世界各地的其他人都在使用这些类库,现在我开始使用VisualStudio2010,我想知道,对于我来说,切换到使用代码契约,而不是常规的旧式if语句是多么好的主意 即,与此相反:Visual studio 2010 在VisualStudio2010 Professional中为类库使用代码契约(即无静态检查)有多好?,visual-studio-2010,c#-4.0,static-analysis,code-contracts,Visual Studio 2010,C# 4.0,Static Analysis,Code Contracts,我创建了一些类库,世界各地的其他人都在使用这些类库,现在我开始使用VisualStudio2010,我想知道,对于我来说,切换到使用代码契约,而不是常规的旧式if语句是多么好的主意 即,与此相反: if (fileName == null) throw new ArgumentNullException("fileName"); 使用以下命令: Contract.Requires(fileName != null); 我问这个问题的原因是我知道静态检查器对我来说是不可用的,所以我对我
if (fileName == null)
throw new ArgumentNullException("fileName");
使用以下命令:
Contract.Requires(fileName != null);
我问这个问题的原因是我知道静态检查器对我来说是不可用的,所以我对我所做的一些编译器无法验证的假设有点紧张。这可能会导致下载类库的人在使用静态检查器时无法编译类库。这一点,再加上我甚至不能重现这个问题的事实,使得修复这个问题变得很烦人,而且我想,如果类库看起来甚至没有开箱即用的编译,那么它就无法与我的类库的质量相媲美
所以我有几个问题:
- 如果您有访问权限,静态检查器是否默认打开?或者在类库中是否有需要打开的设置(因为我没有静态检查器,所以不会打开)
- 我的恐惧是没有根据的吗?上述情景是一个真正的问题吗
编辑:让我澄清一下我的意思 假设我在一个类中有以下方法:
public void LogToFile(string fileName, string message)
{
Contracts.Requires(fileName != null);
// log to the file here
}
然后我有了这个代码:
public void Log(string message)
{
var targetProvider = IoC.Resolve<IFileLogTargetProvider>();
var fileName = targetProvider.GetTargetFileName();
LogToFile(fileName, message);
}
公共作废日志(字符串消息)
{
var targetProvider=IoC.Resolve();
var fileName=targetProvider.GetTargetFileName();
日志文件(文件名、消息);
}
现在,IoC开始解析一些“随机”类,它为我提供了一个文件名。假设对于这个库,我不可能得到一个不会给我非空文件名的类,但是,由于IoC调用的性质,静态分析无法验证这一点,因此可能会假设一个可能的值可能为空
因此,静态分析可能会得出结论,存在使用null
参数调用LogToFile
方法的风险,因此无法构建
我知道我可以给代码添加假设,说编译器应该认为我从该方法返回的文件名
永远不会为空,但是如果我没有静态分析器(VS2010 Professional),上面的代码将为我编译,因此,我可能会把它作为一个沉睡的虫子留给一个有终极目标的人去寻找。换句话说,编译时不会警告这里可能有问题,所以我可能会按原样发布库
那么这是一个真实的场景和问题吗?首先,静态检查器实际上(据我所知)只在终极版/学术版中可用,因此,除非您组织中的每个人都使用它,否则如果他们可能违反不变量,可能不会收到警告 其次,虽然静态分析令人印象深刻,但它不能总是找到可能导致违反不变量的所有路径。然而,这里的好消息是,
Requires
契约在运行时保留——它在IL转换步骤中处理——因此检查在编译时和运行时都存在。这样,它就相当于(但优于)常规的if()
检查
您可以阅读更多关于代码契约编译执行的运行时重写的信息,还可以阅读
编辑:根据我从手册中收集到的信息,我怀疑您描述的情况确实是可能的。但是,我认为这些将是警告而不是编译错误-您可以使用System.Diagnostics.codesanalysis.SuppressMessage()
来抑制它们。拥有静态验证器的代码使用者也可以标记要忽略的特定情况,但如果存在大量此类情况,则肯定会带来不便。今天晚些时候,我将尝试找时间对您的场景进行最终测试(我目前无法访问静态验证器)
有一个几乎专门用于代码契约的方法(如果您还没有看到),它可能包含一些您感兴趣的内容。当
LogToFile
和Log
方法都是库的一部分时,一旦打开静态检查器,您的Log
方法可能无法编译。当您向使用静态检查器编译代码的其他人提供代码时,当然也会发生这种情况。但是,据我所知,您的客户机的静态检查器不会验证您提供的组件的内部。它将根据程序集的公共API静态检查它们自己的代码。所以只要你把DLL发出去,你就没事了
当然,对于实际启用了静态检查器的用户来说,提供一个具有非常恼人的API的库是有变化的,因此我认为,如果您测试了使用静态检查器和不使用静态检查器的API的可用性,则只提供带有合同定义的库是明智的
请注意更改现有的
if(cond)throw ex
调用到Contracts.Requires(cond)
调用,以调用您在以前版本中已经发布的公共API调用。请注意,Requires
方法引发的异常(如果我没有记错的话,则为RequiresViolationException
)与您通常引发的异常不同(为ArgumentException
)。在这种情况下,使用重载。这样,您的API接口保持不变。否;静态分析器永远不会阻止编译成功(除非它崩溃!)
静态分析器将警告您未经验证的前置/后置条件,但不会停止编译。是的,我知道所有这些。我想知道的是,如果分析无法验证参数