在阅读了有关此类问题的其他一些答案后,我仍然得到警告。在此代码段中,我从数据库中提取了一个UserActivation。至此,将始终至少有一个UserActivation。如果还有更多的话,那么一切都变成了梨形...我遵循了一些其他说明,关于如何对未经证实的来源发出警告,但无济于事。警告是:警告83 CodeContracts:要求未经证实:source!= 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;
    }

最佳答案

我会尝试使用其他方法,也许避免使用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。

关于c# - 代码契约(Contract):需要未经证实的来源!= null,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8646954/

10-10 12:33