代码契约:需要未经证实的来源!= null
在阅读了对此类问题的其他一些回答后,我仍然留下警告。在此代码片段中,我从数据库中提取了 UserActivation。至此,总会至少有一个 UserActivation。如果有不止一个东西已经变成了梨形......我按照其他一些说明如何压制有关未经证实的来源的警告,但无济于事。警告是:警告 83 CodeContracts:需要未经证实:来源!= null第161行,具体行见下面的方法。
这是方法
private static UserActivation GetUserActivation(Guid userId)
{
UserActivations userActivations = UserActivation.GetUserActivationsByUser(userId: userId);
Contract.Assume(userActivations != null);
if (userActivations.Count() > 1) // Line Number 161
throw new Exception("More then one user action found in database");
return userActivations[0];
}
我使用的是 CC 版本 1.4.40602.0,此处要求的是 UserActivations 声明。
public class UserActivations : BusinessListBase<UserActivation>
{
#region Constructors
internal UserActivations()
{
}
internal UserActivations(IList<UserActivation> list)
: base(list)
{
}
internal UserActivations(IEnumerable<UserActivation> list)
: base(list)
{
}
这是 GetUserActivationByUser 方法
public static UserActivations GetUserActivationsByUser(User user = null, Guid userId = new Guid())
{
Contract.Requires(user != null || userId != null, "Either user or userId must have a value");
Contract.Ensures(Contract.Result<UserActivations>() != null);
Guid id = new Guid();
if (user != null)
id = user.Id;
else
id = userId;
return new UserActivations(StorageManager.SelectAll(
Criteria.And(
Criteria.EqualTo("UserId", id),
Criteria.EqualTo("Deleted", false))));
}
原始代码是:
Public static UserActivations GetUserActivationsByUser(User user = null, Guid userId = new Guid())
{
Guid id = new Guid();
if (user != null)
id = user.Id;
else
if (userId != Guid.Empty)
id = userId;
else
throw new Exception("Either user or userId must have a value");
UserActivations uas = new UserActivations(StorageManager.SelectAll(
Criteria.And(
Criteria.EqualTo("UserId", id),
Criteria.EqualTo("Deleted", false))));
Contract.Ensures(Contract.Result<UserActivations>() != null);
return uas;
}
After reading over some of the other responses to this type of question I am still left with the warning. In this snippet I pull a UserActivation from my database. By this point there will always be at least one UserActivation. If there is more then one something has gone all pear shaped... I followed some other instructions on how to squelch the warning regarding an unproven source but to no avail.The warning is: Warning 83 CodeContracts: requires unproven: source != null on line 161, see method below for the specific line.
This is the method
private static UserActivation GetUserActivation(Guid userId)
{
UserActivations userActivations = UserActivation.GetUserActivationsByUser(userId: userId);
Contract.Assume(userActivations != null);
if (userActivations.Count() > 1) // Line Number 161
throw new Exception("More then one user action found in database");
return userActivations[0];
}
I am using CC version 1.4.40602.0, As requested here is the UserActivations declaration.
public class UserActivations : BusinessListBase<UserActivation>
{
#region Constructors
internal UserActivations()
{
}
internal UserActivations(IList<UserActivation> list)
: base(list)
{
}
internal UserActivations(IEnumerable<UserActivation> list)
: base(list)
{
}
And here is the GetUserActivationByUser method
public static UserActivations GetUserActivationsByUser(User user = null, Guid userId = new Guid())
{
Contract.Requires(user != null || userId != null, "Either user or userId must have a value");
Contract.Ensures(Contract.Result<UserActivations>() != null);
Guid id = new Guid();
if (user != null)
id = user.Id;
else
id = userId;
return new UserActivations(StorageManager.SelectAll(
Criteria.And(
Criteria.EqualTo("UserId", id),
Criteria.EqualTo("Deleted", false))));
}
The original code was:
Public static UserActivations GetUserActivationsByUser(User user = null, Guid userId = new Guid())
{
Guid id = new Guid();
if (user != null)
id = user.Id;
else
if (userId != Guid.Empty)
id = userId;
else
throw new Exception("Either user or userId must have a value");
UserActivations uas = new UserActivations(StorageManager.SelectAll(
Criteria.And(
Criteria.EqualTo("UserId", id),
Criteria.EqualTo("Deleted", false))));
Contract.Ensures(Contract.Result<UserActivations>() != null);
return uas;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我会尝试使用不同的方法,也许避免使用 linq
Enumerable
扩展方法。UserActivations
类没有自己的一些方法或属性来确定实例拥有多少个元素吗?无论如何,您都不应该使用
Count()
扩展方法来测试序列是否为空,因为它将枚举整个序列(如果该序列未实现ICollection
代码>)。或者,正如 Pavel Gatilov 指出的那样,如果对象实现了 IQueryable,Count 可能会意外执行数据库查询。在这里,这不是什么大问题,您期望只有一个元素,但在序列可能通常包含数千个元素的情况下,这可能是一个大问题。相反,您应该使用
Any()
扩展方法。不过,由于从合约分析器的角度来看,使用 Any() 可能不会改变事情,因此您应该使用 UserActivations 类的 Count 属性(假设它实现了 ICollection,例如例子)。
也许您可以通过这种方式帮助合同分析器:
如果您控制
UserActivations
类,更好的解决方案是将Contract.Ensures
添加到GetUserActivationsByUser
> 表示该方法永远不会返回 null。I would try using a different method, perhaps avoiding the linq
Enumerable
extension methods. Doesn't theUserActivations
class have some method or property of its own to determine how many elements an instance holds?In any event, you shouldn't use the
Count()
extension method to test whether a sequence is empty, because it will enumerate the entire sequence (if the sequence does not implementICollection
). Or, as Pavel Gatilov pointed out, if the object implementsIQueryable
, Count may unexpectedly execute a database query.That's not a big deal here, where you expect to have one element, but it could be a big deal in cases where a sequence might regularly have thousands of elements. Instead, you should use the
Any()
extension method.Since using
Any()
probably won't change things from the contract analyzer's point of view, though, you should use the UserActivations class'sCount
property (assuming it implements ICollection, for example).Perhaps you can help the contract analyzer this way:
A better solution, if you control the
UserActivations
class, would be to addContract.Ensures
toGetUserActivationsByUser
to say that the method will never return null.检查您的构建日志。您错误地使用了
Contract.Ensures
。您应该收到有关错误使用的警告,如下所示:您的方法应该是:
我无法证明,但我想这可能会让验证者生气。
事实上,如果我打开运行时检查,您的代码甚至无法编译:ccrewrite 将失败。
Check your build log. You are using
Contract.Ensures
incorrectly. You should have a warning for the incorrect usage, like this one:Your method should be:
I cannot prove, but I suppose this might make the verifier mad.
In fact, if I turn on run-time checks, your code won't even compile: the ccrewrite will fail.