Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# LINQ,在模型中处理Null_C#_Asp.net_Linq - Fatal编程技术网

C# LINQ,在模型中处理Null

C# LINQ,在模型中处理Null,c#,asp.net,linq,C#,Asp.net,Linq,我试图把平均数传递给我的观点。AverageRating是在Icollection of Review模型中查询项目的结果。审查模型具有评级属性。然而,我得到了这样的信息: System.ArgumentNullException 无论何时执行get,都会发生这种情况,这是可以理解的。但是,当我的代码如下所示时,如何最好地处理模型或其他地方的空异常: public class MyModel { //Querying this navigation property

我试图把平均数传递给我的观点。AverageRating是在Icollection of Review模型中查询项目的结果。审查模型具有评级属性。然而,我得到了这样的信息:

System.ArgumentNullException

无论何时执行get,都会发生这种情况,这是可以理解的。但是,当我的代码如下所示时,如何最好地处理模型或其他地方的空异常:

public class MyModel
{

        //Querying this navigation property
        public ICollection<Review> Reviews { get; set; }

        public double? AverageRating
        {
        get
        { 
            //check that this is not null / handle null
            return Math.Round(Reviews.Average(c => c.Rating), 1);
        }

        }

}
return Math.Round(Reviews?.Average(c => c.Rating) ?? 0.0, 1);
return Math.Round(Reviews?.Average(c => c?.Rating ?? 0.0) ?? 0.0, 1);

您可以使用
DefaultIfEmpty
为空集合设置
0
值,并且要从
平均值
计算中排除可能的空值,您应该消除它们

    public double? AverageRating
    {
        get
        {
            if (Reviews == null)
            {
                return null;
            }
            return Math.Round(Reviews.Where(x => x.Rating.HasValue).Select(x => x.Rating).DefaultIfEmpty(0).Average().Value, 1);
        }
    }
如果您使用的是C#6.0,那么可以使用null传播来帮助指定默认场景

代码最终将如下所示:

public class MyModel
{

        //Querying this navigation property
        public ICollection<Review> Reviews { get; set; }

        public double? AverageRating
        {
        get
        { 
            //check that this is not null / handle null
            return Math.Round(Reviews.Average(c => c.Rating), 1);
        }

        }

}
return Math.Round(Reviews?.Average(c => c.Rating) ?? 0.0, 1);
return Math.Round(Reviews?.Average(c => c?.Rating ?? 0.0) ?? 0.0, 1);
这利用null传播来确保在访问
Average
扩展方法之前,Reviews集合不为null

如果单个项为NULL,则可以在lambda内部扩展检查,并使用以下内容:

public class MyModel
{

        //Querying this navigation property
        public ICollection<Review> Reviews { get; set; }

        public double? AverageRating
        {
        get
        { 
            //check that this is not null / handle null
            return Math.Round(Reviews.Average(c => c.Rating), 1);
        }

        }

}
return Math.Round(Reviews?.Average(c => c.Rating) ?? 0.0, 1);
return Math.Round(Reviews?.Average(c => c?.Rating ?? 0.0) ?? 0.0, 1);
这将防止审查为空或审查的项目为空

这里有一把小提琴在演奏:

如果需要跳过将空值转换为0,则可以先使用
Where
语句从集合中删除空项

return Math.Round(Reviews?.Where(c => c?.Rating != null).Average(c => c.Rating) ?? 0.0, 1);
这样,在将其处理为
Average
之前,将从列表中删除任何空项

编辑

根据下面的注释,您可以使用
DefaultIfEmpty
处理序列本身为空的情况,如下所示:

return Math.Round(Reviews?.DefaultIfEmpty().Average(c => c?.Rating ?? 0.0) ?? 0.0, 1);
调用
DefaultIfEmpty
将返回一个
IEnumerable
将在其中包含一个null元素。然后在
平均过程中将其过滤掉,并返回0

这也可以与本文中的其他方法相结合。fiddle已经更新为使用
DefaultIfEmpty

什么是空值的测试示例? 首先,让我们假设
null
表示
unknown
。埃里克·利珀特(Eric Lippert)的研究提供了一个很好的理由。它可以进一步追溯到SQL的设计和三态逻辑的原理。
null
集合不是空的,就像
null
int?
不是零一样

但即使您不同意,正确使用空值也有两种基本理念:

1.防止空值 只需调整模型,以便在对象的生存期内始终防止空值。这并不总是可以通过类型系统实现(特别是在使用.NET序列化时)。这也可能会在某些地方产生大量额外的样板代码,因此请明智地使用它:

public class Model
{
    // is non-null in any Model instance
    public IReadOnlyList<ModelItem> Items { get; }

    public Model(IEnumerable<ModelItem> items)
    {
        Items = new List<ModelItems>(items); // does not check if items contains null
    }
}
请注意,
Average
不会使用空序列抛出
invalidoOperationException
。与不可为空的变量不同,应为不可为空的类型添加额外的检查

还要注意的是,代码没有试图将
null
s解析为除
null
以外的任何内容。如果您的
null
在某个地方得到处理,它很可能是应用程序业务逻辑的一部分,并且应该位于相应的层中(例如,处理与没有特定属性的早期版本模型的向后兼容性的代码,将其作为
null
返回)


但是,如果您的模型类固有地假设
null
集合是空集合(出于可读性和维护原因,我强烈建议不要这样做),那么null确实不应该传播,应该在该类内部处理,例如使用合并操作符(
??
).

此实现可以满足您的需要:

public double? AverageRating
{
    get
    {
        return Reviews?.Average(x => x?.Rating);
    }
}
它将处理
审核
(由于在
审核
后使用
,它将返回


由于在
x

之后使用
,因此它将处理
为空的
个人
评论(在计算平均值时将忽略这些评论)。这种情况下的例外情况可能是因为
Reviews
集合为
null
,或者
Reviews
集合项之一为
null
。空集合和
null
之间的语义区别是什么?包含
null
元素的集合的含义是什么?@mjwills,Review.Rating是一个整数。@ZdeněkJelínek Jelínek我想如果一个Review集合项为null,则表示我还没有评级。@Sefe很好!谢谢。我建议使用
null
,因为它更能反映“我不知道”而不是“非常低的分数”。使用
返回Math.Round(Reviews?.Average(c=>c?.Rating?0.0)??0.0,1)我得到
无效操作异常:序列不包含任何元素
。我的视图:
@Html.DisplayFor(modelItem=>item.AverageRating)
。这个问题的可能解决方案是什么?我有点不知所措,因为我对这一切都很陌生……我犯了一个错误<代码>平均值
需要至少包含一个元素的序列才能正确处理。解决方案是在调用
Average
之前检查元素,或者使用
DefaultIfEmpty
要求序列至少有一个元素才能正确处理。
请注意,并非所有序列都是如此(例如,可为null的int序列)。这是有效的!我现在可以看到在我看来,它是空的,这是我想要的平均评级。我想我会用三元组检查它是否为空,然后有一个像“还没有评级”这样的文本。谢谢你的努力,非常感谢!