一个关于可空布尔类型的奇怪的事情,c#中的And和Or
本文关键字:中的 Or And 一个 于可空 类型 布尔 | 更新日期: 2023-09-27 18:11:45
我对以下代码有一个奇怪的问题:
!isActive.HasValue || (isActive.HasValue && x.IsActive == isActive.Value)
isActive
是bool?
类型,所以如果isActive
是null
,那么我将得到以下错误:
可空对象必须有一个值。
你知道吗?谢谢你的帮助!
更新1:public static List<User> Select(int userId, bool? isActive = null)
{
var dl = DataLayer.GetDataContext();
return dl.Users.Where(x => x.ID == userId
&& (!isActive.HasValue || (isActive.HasValue && x.IsActive == isActive.Value))).ToList();
}
这是我得到这个错误的样本函数。我知道这很奇怪!如果我像下面这样修改,它就可以工作了:
!isActive.HasValue || (isActive.HasValue && x.IsActive == isActive)
我明白这个错误的意思,但是我不明白为什么。我想应该能行。所以我把它叫做奇怪的东西!
更新2:- x。IsActive是bool类型,不是bool?我很确定:)
- DataLayer.GetDataContext()用于Linq to SQL。
是否可能是因为我使用SQL Server?
感谢大家的帮助
由于它是Linq-to-SQL,那么它可能不会短路或以正确的顺序计算表达式部分。我没有使用过它,但从我的理解它读取你的lambda表达式的内容,并将其转换为一个接近等效的SQL语句;它实际上并不像c#代码那样执行
即便如此,当值固定时,对每个项进行检查似乎有点多。您可以这样重写该方法:
public static List<User> Select(int userId, bool? isActive = null)
{
var dl = DataLayer.GetDataContext();
var users = dl.Users.Where(x => x.ID == userID);
if (!isActive.HasValue)
{
return users.ToList();
}
else
{
bool isActiveValue = isActive.Value;
return users.Where(x => x.IsActive == isActiveValue).ToList();
}
}
这样,如果生成的SQL查询不适用,就不会有额外的约束。编辑:更新了它,所以除此之外,没有可空的布尔值被传递到你的查询。
您的代码中有两个不同的isActive
值,因此看起来您在第二次检查时遗漏了x
:
!isActive.HasValue || (x.isActive.HasValue && (x.IsActive == isActive.Value))
----^
我还在相等性检查周围添加了括号,以消除顺序或操作的混淆
哦,这是因为LINQ中的查询生成器。可能有一种方法可以在一个查询中执行您的意图(实际上,它听起来像您在q中更新的代码就是这样做的),但是要做的直接的事情是将其拆分为两个查询,因为您事先知道isActive
的值。这样,您就不必担心查询生成器可能会做什么或可能不会做什么。
对于这个问题,您不妨将这两个函数完全分开,只是为了使将来的维护者更难以意外地落入相同的陷阱:
public static List<User> Select(int userId)
{
return DataLayer.GetDataContext().Users.Where(x => x.ID == userId).ToList();
}
public static List<User> Select(int userId, bool isActive)
{
return DataLayer.GetDataContext().Users.Where(x => x.ID == userId && x.IsActive == isActive).ToList();
}
你的代码不应该在那一行失败。
我猜它在你的if
块的某个地方失败了(我假设这就是这个语句的目的)。如果isActive
是null
,第一个条件将返回true。如果你尝试在块内使用isActive,你会得到Nullable错误。
如果这样做,代码在哪里失败?
public static List<User> Select(int userId, bool? isActive = null)
{
var dl = DataLayer.GetDataContext();
return dl.Users.Where(x => E(userId, isActive, x)).ToList();
}
static bool E(int userId, bool? isActive, User x)
{
return x.ID == userId && D(isActive, x);
}
static bool D(bool? isActive, User x)
{
return (!isActive.HasValue || C(isActive, x));
}
static bool C(bool? isActive, User x)
{
return (isActive.HasValue && B(isActive, x));
}
static bool B(bool? isActive, User x)
{
return x.IsActive == isActive.Value;
}
将其类型从bool改为bool?
bool? IsActive = false;