此代码编译:
static void Main(string[] args)
{
bool? fred = true;
if (fred == true)
{
Console.WriteLine("fred is true");
}
else if (fred == false)
{
Console.WriteLine("fred is false");
}
else
{
Console.WriteLine("fred is null");
}
}
此代码不编译。
static void Main(string[] args)
{
bool? fred = true;
if (fred)
{
Console.WriteLine("fred is true");
}
else if (!fred)
{
Console.WriteLine("fred is false");
}
else
{
Console.WriteLine("fred is null");
}
}
我认为if(booleanExpression == true)应该是冗余。为什么不是这种情况呢?
答案 0 :(得分:58)
没有从Nullable<bool>
到bool
的隐式转换。 是从bool
到Nullable<bool>
的隐式转换,这就是第一个版本中每个bool常量发生的(用语言术语)。然后应用bool operator==(Nullable<bool>, Nullable<bool>
运算符。 (这与其他提升的运算符不完全相同 - 结果只是bool
,而不是Nullable<bool>
。)
换句话说,表达式'fred == false'的类型为bool
,而表达式'fred'的类型为Nullable<bool>
,因此您不能将其用作“if”表达
编辑:要回答评论,从来没有从Nullable<T>
到T
的隐式转换,并且有充分的理由 - 隐式转换不应该抛出异常,除非您希望null
被隐式转换为default(T)
并没有其他可以做的事情。
另外,如果 隐式转换都是双向的,那么像“nullable + nonNullable”这样的表达式会非常混乱(对于支持+的类型,如int
)。 +(T?,T?)和+(T,T)都可用,具体取决于转换的操作数 - 但结果可能非常不同!
我完全支持从Nullable<T>
到T
的明确转换。
答案 1 :(得分:8)
因为fred不是布尔值。它是一个结构,它有一个名为IsNull或HasValue的布尔属性,或者其他......名为fred的对象是包含布尔值和值的复合合成对象,而不是基本布尔本身......
下面,例如,如何实现Nullable Int。通用Nullable几乎可以肯定地实现(但一般来说)。您可以在此处看到隐式和显式转换是如何实现的。
public struct DBInt
{
// The Null member represents an unknown DBInt value.
public static readonly DBInt Null = new DBInt();
// When the defined field is true, this DBInt represents a known value
// which is stored in the value field. When the defined field is false,
// this DBInt represents an unknown value, and the value field is 0.
int value;
bool defined;
// Private instance constructor. Creates a DBInt with a known value.
DBInt(int value)
{
this.value = value;
this.defined = true;
}
// The IsNull property is true if this DBInt represents an unknown value.
public bool IsNull { get { return !defined; } }
// The Value property is the known value of this DBInt, or 0 if this
// DBInt represents an unknown value.
public int Value { get { return value; } }
// Implicit conversion from int to DBInt.
public static implicit operator DBInt(int x)
{ return new DBInt(x); }
// Explicit conversion from DBInt to int. Throws an exception if the
// given DBInt represents an unknown value.
public static explicit operator int(DBInt x)
{
if (!x.defined) throw new InvalidOperationException();
return x.value;
}
public static DBInt operator +(DBInt x)
{ return x; }
public static DBInt operator -(DBInt x)
{ return x.defined? -x.value: Null; }
public static DBInt operator +(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value + y.value: Null;
}
public static DBInt operator -(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value - y.value: Null;
}
public static DBInt operator *(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value * y.value: Null;
}
public static DBInt operator /(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value / y.value: Null;
}
public static DBInt operator %(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value % y.value: Null;
}
public static DBBool operator ==(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value == y.value: DBBool.Null;
}
public static DBBool operator !=(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value != y.value: DBBool.Null;
}
public static DBBool operator >(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value > y.value: DBBool.Null;
}
public static DBBool operator <(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value < y.value: DBBool.Null;
}
public static DBBool operator >=(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value >= y.value: DBBool.Null;
}
public static DBBool operator <=(DBInt x, DBInt y)
{
return x.defined && y.defined?
x.value <= y.value: DBBool.Null;
}
public override bool Equals(object o)
{
try { return (bool) (this == (DBInt) o); }
catch { return false; }
}
public override int GetHashCode()
{ return (defined)? value: 0; }
public override string ToString()
{ return (defined)? .ToString(): "DBInt.Null"; }
}
答案 2 :(得分:3)
声明Nullable<bool> == true
隐含地检查Nullable<bool> == (Nullable<bool>)true
。
请注意Nullable<bool>
本身不是布尔值。它是布尔值的包装器,也可以设置为null。
答案 3 :(得分:1)
完整地说明了实施问题:Fred
属于Nullable<bool>
类型,而!
运算符未定义为Nullable<bool>
。我们没有理由!
Nullable<bool>
上的bool
运算符定义为static void Main(string[] args)
{
bool? fred = null;
if (!fred)
{
Console.WriteLine("you should not see this");
}
else
{
Console.WriteLine("Microsoft fixed this in 4.5!!!");
}
}
。
引用微软:
当与可空类型进行比较时,如果其中一个 可空类型为null,比较总是被评估为false。
该规则未提及隐式转换。它只是一个任意约定,旨在保证没有布尔表达式具有异常。一旦规则到位,我们就知道如何编写代码。可悲的是,微软错过了这位一元运营商。为了与二元运算符行为保持一致,以下代码应该有一个圆满的结局。
因此
fred==false
我敢打赌,有些程序员现在必须编写{{1}},而Microsoft修复了这个看似最后一个空问题。
答案 4 :(得分:0)
如果将fred强制转换为boolean,它将编译:
if (( bool )fred )
(...)
我认为当你比较布尔时? bool,编译器做一个implicite强制转换,进行比较,然后返回true或false。结果:表达式评估为bool。
当你不比较布尔?某事,表达式评价为bool?,谁在那里非法。
答案 5 :(得分:0)
从技术上讲,如果你有一个true运算符的实现,那么裸条件测试不需要隐式转换为bool。
bool? nullableBool = null;
SqlBoolean sqlBoolean = SqlBoolean.Null;
bool plainBool = sqlBoolean; // won't compile, no implicit conversion
if (sqlBoolean) { } // will compile, SqlBoolean implements true operator
最初的问题是寻找一个null样式的SQL样式实现,其中null被视为更像未知,而Nullable实现更像是添加null作为额外的可能值。例如比较:
if (((int?)null) != 0) { } //block will execute since null is "different" from 0
if (SqlInt32.Null != 0) { } // block won't execute since "unknown" might have value 0
System.Data.SqlTypes