C# 为什么代码合同会声称;“确保是错误的”;这个代码?
这是我的一个类中的构造函数:C# 为什么代码合同会声称;“确保是错误的”;这个代码?,c#,uwp,code-contracts,C#,Uwp,Code Contracts,这是我的一个类中的构造函数: public SemanticVersion(string version) { Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(version)); Contract.Ensures(MajorVersion >= 0); Contract.Ensures(MinorVersion >= 0); Contract.Ensures(Patch
public SemanticVersion(string version)
{
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(version));
Contract.Ensures(MajorVersion >= 0);
Contract.Ensures(MinorVersion >= 0);
Contract.Ensures(PatchVersion >= 0);
Contract.Ensures(PrereleaseVersion != null);
Contract.Ensures(BuildVersion != null);
var match = SemanticVersionRegex.Match(version);
if (!match.Success)
{
var message = $"The version number '{version}' is not a valid semantic version number.";
throw new ArgumentException(message, nameof(version));
}
MajorVersion = int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture);
MinorVersion = int.Parse(match.Groups["minor"].Value, CultureInfo.InvariantCulture);
PatchVersion = int.Parse(match.Groups["patch"].Value, CultureInfo.InvariantCulture);
PrereleaseVersion = match.Groups["prerelease"].Success
? new Maybe<string>(match.Groups["prerelease"].Value)
: Maybe<string>.Empty;
BuildVersion = match.Groups["build"].Success
? new Maybe<string>(match.Groups["build"].Value)
: Maybe<string>.Empty;
}
公共语义版本(字符串版本)
{
Contract.Requires(!string.IsNullOrEmpty(version));
合同(主要版本>=0);
合同(MinorVersion>=0);
合同(版本>=0);
合同(预发布版本!=null);
Contract.Contract(BuildVersion!=null);
var match=SemanticVersionRegex.match(版本);
如果(!match.Success)
{
var message=$“版本号“{version}”不是有效的语义版本号。”;
抛出新的ArgumentException(消息,nameof(版本));
}
MajorVersion=int.Parse(match.Groups[“major”].Value,CultureInfo.InvariantCulture);
MinorVersion=int.Parse(match.Groups[“minor”].Value,CultureInfo.InvariantCulture);
PatchVersion=int.Parse(match.Groups[“patch”].Value,CultureInfo.InvariantCulture);
PrereleaseVersion=match.Groups[“prerelease”]。成功
?新的可能(匹配组[“预发布”].值)
:可能是空的;
BuildVersion=match.Groups[“build”]。成功
?新的可能(match.Groups[“build”].Value)
:可能是空的;
}
代码收缩静态检查器标记错误:
警告:CodeContracts:确保为false:PrereleaseVersion!=空的
可能是包含零个或一个元素的集合
就我所见,唯一可以为null的方法是在分配异常之前是否存在异常,这将使需求不相关。我是不是变得代码盲了?你能看到问题吗
更新:发布可能的实施以回应评论
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
namespace TA.CoreTypes
{
/// <summary>
/// Represents an object that may or may not have a value (strictly, a collection of zero or one elements). Use
/// LINQ expression
/// <c>maybe.Any()</c> to determine if there is a value. Use LINQ expression
/// <c>maybe.Single()</c> to retrieve the value.
/// </summary>
/// <typeparam name="T">The type of the item in the collection.</typeparam>
public class Maybe<T> : IEnumerable<T>
{
private static readonly Maybe<T> EmptyInstance = new Maybe<T>();
private readonly IEnumerable<T> values;
/// <summary>
/// Initializes a new instance of the <see cref="Maybe{T}" /> with no value.
/// </summary>
private Maybe()
{
values = new T[0];
}
/// <summary>
/// Initializes a new instance of the <see cref="Maybe{T}" /> with a value.
/// </summary>
/// <param name="value">The value.</param>
public Maybe(T value)
{
Contract.Requires(value != null);
values = new[] {value};
}
/// <summary>
/// Gets an instance that does not contain a value.
/// </summary>
/// <value>The empty instance.</value>
public static Maybe<T> Empty
{
get
{
Contract.Ensures(Contract.Result<Maybe<T>>() != null);
return EmptyInstance;
}
}
public IEnumerator<T> GetEnumerator()
{
Contract.Ensures(Contract.Result<IEnumerator<T>>() != null);
return values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
Contract.Ensures(Contract.Result<IEnumerator>() != null);
return GetEnumerator();
}
[ContractInvariantMethod]
private void ObjectInvariant()
{
Contract.Invariant(values != null);
}
[Pure]
public override string ToString()
{
Contract.Ensures(Contract.Result<string>() != null);
if (Equals(Empty)) return "{no value}";
return this.Single().ToString();
}
}
public static class MaybeExtensions
{
public static bool None<T>(this Maybe<T> maybe)
{
if (maybe == null) return true;
if (maybe == Maybe<T>.Empty) return true;
return !maybe.Any();
}
}
}
使用系统集合;
使用System.Collections.Generic;
使用System.Diagnostics.Contracts;
使用System.Linq;
命名空间TA.CoreTypes
{
///
///表示一个对象,该对象可能有值,也可能没有值(严格地说,是零个或一个元素的集合)。使用
///LINQ表达式
///可以使用.Any()来确定是否存在值。使用LINQ表达式
///可以使用.Single()来检索该值。
///
///集合中项目的类型。
公共类:IEnumerable
{
private static readonly Maybe EmptyInstance=new Maybe();
私有只读IEnumerable值;
///
///初始化的新实例,但不包含任何值。
///
二等兵
{
值=新的T[0];
}
///
///使用值初始化的新实例。
///
///价值。
公共价值(T值)
{
Contract.Requires(值!=null);
values=new[]{value};
}
///
///获取不包含值的实例。
///
///空实例。
公共静态可能是空的
{
得到
{
Contract.sure(Contract.Result()!=null);
返回空站;
}
}
公共IEnumerator GetEnumerator()
{
Contract.sure(Contract.Result()!=null);
返回值。GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
Contract.sure(Contract.Result()!=null);
返回GetEnumerator();
}
[收缩变量法]
私有无效对象变量()
{
Contract.Invariant(值!=null);
}
[纯]
公共重写字符串ToString()
{
Contract.sure(Contract.Result()!=null);
if(等于(空))返回“{no value}”;
返回此.Single().ToString();
}
}
公共静态类可以扩展
{
公共静态布尔无(这可能)
{
if(maybe==null)返回true;
if(maybe==maybe.Empty)返回true;
返回!可能。任何();
}
}
}
如果匹配,则可能为null
。Success
为false
试试这个
public SemanticVersion(string version)
{
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(version));
Contract.Ensures(MajorVersion >= 0);
Contract.Ensures(MinorVersion >= 0);
Contract.Ensures(PatchVersion >= 0);
Contract.Ensures(PrereleaseVersion != null);
Contract.Ensures(BuildVersion != null);
var match = SemanticVersionRegex.Match(version);
if (!match.Success)
{
// set the values here
PrereleaseVersion = Maybe<string>.Empty;
BuildVersion = Maybe<string>.Empty;
var message = $"The version number '{version}' is not a valid semantic version number.";
throw new ArgumentException(message, nameof(version));
}
MajorVersion = int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture);
MinorVersion = int.Parse(match.Groups["minor"].Value, CultureInfo.InvariantCulture);
PatchVersion = int.Parse(match.Groups["patch"].Value, CultureInfo.InvariantCulture);
PrereleaseVersion = match.Groups["prerelease"].Success
? new Maybe<string>(match.Groups["prerelease"].Value)
: Maybe<string>.Empty;
BuildVersion = match.Groups["build"].Success
? new Maybe<string>(match.Groups["build"].Value)
: Maybe<string>.Empty;
}
似乎类上唯一的mutator方法可能是构造函数本身。其他任何一种方法都能得到东西。因此,您可以将PureAttribute
放在类级别,以提示分析器整个类都是纯的,因为它毕竟是不可变的,这难道不是一个Maybe的点吗,或者您得到了一些东西,或者您得到了一个空Maybe,但是您永远不会得到null?你不能改变一个Maybe中的值,你只能创建一个包含新值的新Maybe
另外,我在使用静态分析器和使用契约时总是遇到问题。即使指定了对象不变量,也可以确保构造函数中的属性(特别是可变属性)具有;我不太清楚这是为什么
无论如何,如果您有不可变的属性,那么下面的代码应该可以工作:
// If this class is immutable, consider marking it with:
// [Pure]
public class SemanticVersion
{
private readonly int _majorVersion;
private readonly int _minorVersion;
private readonly int _patchVersion;
private readonly Maybe<T> _buildVersion;
private readonly Maybe<T> _prereleaseVersion;
public SemanticVersion(string version)
{
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(version));
var match = SemanticVersionRegex.Match(version);
if (!match.Success)
{
var message = $"The version number '{version}' is not a valid semantic version number.";
throw new ArgumentException(message, nameof(version));
}
_majorVersion = int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture);
_minorVersion = int.Parse(match.Groups["minor"].Value, CultureInfo.InvariantCulture);
_patchVersion = int.Parse(match.Groups["patch"].Value, CultureInfo.InvariantCulture);
_prereleaseVersion = match.Groups["prerelease"].Success
? new Maybe<string>(match.Groups["prerelease"].Value)
: Maybe<string>.Empty;
_buildVersion = match.Groups["build"].Success
? new Maybe<string>(match.Groups["build"].Value)
: Maybe<string>.Empty;
}
[ContractInvariantMethod]
private void ObjectInvariants()
{
Contract.Invariant(_majorVersion >= 0);
Contract.Invariant(_minorVersion >= 0);
Contract.Invariant(_patchVersion >= 0);
Contract.Invariant(_prereleaseVersion != null);
Contract.Invariant(_buildVersion != null);
}
// Properties that only contain getters are automatically
// considered Pure by Code Contracts. But also, this point
// is moot if you make the entire class Pure if it's
// immutable.
public int MajorVersion => _majorVersion;
public int MinorVersion => _minorVersion;
public int PatchVersion => _patchVersion;
public Maybe<T> PrereleaseVersion => _prereleaseVersion;
public Maybe<T> BuildVersion => _buildVersion;
}
<代码> / /如果该类是不可变的,请考虑将其标记为:
//[纯]
公共类语义版本
{
专用只读内部版本;
私有只读输入;
专用只读int_补丁版本;
私有只读版本;
私有的只读版本;
公共语义版本(字符串版本)
{
Contract.Requires(!string.IsNullOrEmpty(version));
var match=SemanticVersionRegex.match(版本);
如果(!match.Success)
{
var message=$“版本号“{version}”不是有效的语义版本号。”;
抛出新的ArgumentException(消息,nameof(版本));
}
_majorVersion=int.Parse(match.Groups[“major”].Value,CultureInfo.InvariantCulture);
_minorVersion=int.Parse(match.Groups[“minor”].Value,CultureInfo.InvariantCulture);
_patchVersion=int.Parse(match.Groups[“patch”].Value,CultureInfo.InvariantCulture);
// If this class is immutable, consider marking it with:
// [Pure]
public class SemanticVersion
{
private readonly int _majorVersion;
private readonly int _minorVersion;
private readonly int _patchVersion;
private readonly Maybe<T> _buildVersion;
private readonly Maybe<T> _prereleaseVersion;
public SemanticVersion(string version)
{
Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(version));
var match = SemanticVersionRegex.Match(version);
if (!match.Success)
{
var message = $"The version number '{version}' is not a valid semantic version number.";
throw new ArgumentException(message, nameof(version));
}
_majorVersion = int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture);
_minorVersion = int.Parse(match.Groups["minor"].Value, CultureInfo.InvariantCulture);
_patchVersion = int.Parse(match.Groups["patch"].Value, CultureInfo.InvariantCulture);
_prereleaseVersion = match.Groups["prerelease"].Success
? new Maybe<string>(match.Groups["prerelease"].Value)
: Maybe<string>.Empty;
_buildVersion = match.Groups["build"].Success
? new Maybe<string>(match.Groups["build"].Value)
: Maybe<string>.Empty;
}
[ContractInvariantMethod]
private void ObjectInvariants()
{
Contract.Invariant(_majorVersion >= 0);
Contract.Invariant(_minorVersion >= 0);
Contract.Invariant(_patchVersion >= 0);
Contract.Invariant(_prereleaseVersion != null);
Contract.Invariant(_buildVersion != null);
}
// Properties that only contain getters are automatically
// considered Pure by Code Contracts. But also, this point
// is moot if you make the entire class Pure if it's
// immutable.
public int MajorVersion => _majorVersion;
public int MinorVersion => _minorVersion;
public int PatchVersion => _patchVersion;
public Maybe<T> PrereleaseVersion => _prereleaseVersion;
public Maybe<T> BuildVersion => _buildVersion;
}