36

このコードは以下をコンパイルします。

private 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");
}

このコードはコンパイルされませ

private 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)私は冗長性であるはずだと思った。なぜこの場合ではないのですか?

4

6 に答える 6

60

Nullable<bool>からへの暗黙的な変換はありませんbool。からto への暗黙の変換がありそれが最初のバージョンの各 bool 定数に (言語用語で) 起こることです。次に、演算子が適用されます。(これは、他の持ち上げられた演算子とまったく同じではありません。結果は であり、 ではありません。)boolNullable<bool>bool operator==(Nullable<bool>, Nullable<bool>boolNullable<bool>

言い換えれば、式 'fred == false' は型boolであるのに対し、式 'fred' は型であるNullable<bool>ため、「if」式として使用することはできません。

編集:コメントに答えるために、からNullable<T>への暗黙的な変換は決してありません.T正当な理由があります.暗黙的な変換は例外をスローすべきではありませnulldefault(T).

また、暗黙の変換が双方向にある場合、 nullable + nonNullable」のような式は非常に混乱を招きます (+ をサポートする型の場合、 などint)。+(T?, T?) と +(T, T) の両方が、変換されたオペランドに応じて利用可能になりますが、結果は大きく異なる可能性があります!

Nullable<T>からへの明示的な変換のみを行うという決定には、私は 100% 賛成ですT

于 2009-01-15T16:21:24.317 に答える
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"; }   
   }
于 2009-01-15T16:20:40.823 に答える
3

ステートメントNullable<bool> == trueは暗黙的にチェックしていNullable<bool> == (Nullable<bool>)trueます。

Nullable<bool>それ自体はブール値ではないことに注意してください。null にも設定できるブール値のラッパーです。

于 2009-01-15T16:24:10.737 に答える
0

fred をブール値にキャストすると、次のようにコンパイルされます。

  if (( bool )fred )
      (...)

ブールを比較すると思いますか?bool にする場合、コンパイラは暗黙のキャストを行い、比較を行ってから、true または false を返します。Result : 式は bool に評価されます。

ブールを比較しないときは?何かに、式はブール値に評価されますか?、誰がそこで違法です。

于 2009-01-15T16:26:32.463 に答える
0

技術的には、真の演算子の実装がある場合、裸の条件付きテストは 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

于 2009-07-29T20:48:32.853 に答える