代码契约:需要未经证实的来源!= null

发布于 2024-12-22 19:53:04 字数 2443 浏览 1 评论 0原文

在阅读了对此类问题的其他一些回答后,我仍然留下警告。在此代码片段中,我从数据库中提取了 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

埖埖迣鎅 2024-12-29 19:53:04

我会尝试使用不同的方法,也许避免使用 linq Enumerable 扩展方法。 UserActivations 类没有自己的一些方法或属性来确定实例拥有多少个元素吗?

无论如何,您都不应该使用 Count() 扩展方法来测试序列是否为空,因为它将枚举整个序列(如果该序列未实现 ICollection代码>)。或者,正如 Pavel Gatilov 指出的那样,如果对象实现了 IQueryable,Count 可能会意外执行数据库查询。

在这里,这不是什么大问题,您期望只有一个元素,但在序列可能通常包含数千个元素的情况下,这可能是一个大问题。相反,您应该使用 Any() 扩展方法。

不过,由于从合约分析器的角度来看,使用 Any() 可能不会改变事情,因此您应该使用 UserActivations 类的 Count 属性(假设它实现了 ICollection,例如例子)。

也许您可以通过这种方式帮助合同分析器:

private static UserActivation GetUserActivation(Guid userId) 
{ 
    UserActivations userActivations = UserActivation.GetUserActivationsByUser(userId: userId); 

    IEnumerable<UserActivation> e = (IEnumerable<UserActivation>)userActivations;

    Contract.Assume(e != null); 

    if (e.Count() > 1) // Line Number 161 
        throw new Exception("More then one user action found in database"); 

    return userActivations[0]; 
} 

如果您控制 UserActivations 类,更好的解决方案是将 Contract.Ensures 添加到 GetUserActivationsByUser > 表示该方法永远不会返回 null。

I would try using a different method, perhaps avoiding the linq Enumerable extension methods. Doesn't the UserActivations 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 implement ICollection). Or, as Pavel Gatilov pointed out, if the object implements IQueryable, 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's Count property (assuming it implements ICollection, for example).

Perhaps you can help the contract analyzer this way:

private static UserActivation GetUserActivation(Guid userId) 
{ 
    UserActivations userActivations = UserActivation.GetUserActivationsByUser(userId: userId); 

    IEnumerable<UserActivation> e = (IEnumerable<UserActivation>)userActivations;

    Contract.Assume(e != null); 

    if (e.Count() > 1) // Line Number 161 
        throw new Exception("More then one user action found in database"); 

    return userActivations[0]; 
} 

A better solution, if you control the UserActivations class, would be to add Contract.Ensures to GetUserActivationsByUser to say that the method will never return null.

客…行舟 2024-12-29 19:53:04

检查您的构建日志。您错误地使用了 Contract.Ensures。您应该收到有关错误使用的警告,如下所示:

警告 CC1025:CodeContracts:在合约块之后,发现使用了合约块中定义的局部变量“dataEvents”

您的方法应该是:

public static UserActivations GetUserActivationsByUser(User user = null, Guid userId = new Guid())
{
    Contract.Ensures(Contract.Result<UserActivations>() != null);

    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))));

    return uas;
}

我无法证明,但我想这可能会让验证者生气。

事实上,如果我打开运行时检查,您的代码甚至无法编译:ccrewrite 将失败。

Check your build log. You are using Contract.Ensures incorrectly. You should have a warning for the incorrect usage, like this one:

warning CC1025: CodeContracts: After contract block, found use of local variable 'dataEvents' defined in contract block

Your method should be:

public static UserActivations GetUserActivationsByUser(User user = null, Guid userId = new Guid())
{
    Contract.Ensures(Contract.Result<UserActivations>() != null);

    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))));

    return uas;
}

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文