لماذا bools قيم الفارغة لن تسمح إذا (قيم الفارغة) ولكن لا تسمح إذا (قيم الفارغة == صحيح)؟

StackOverflow https://stackoverflow.com/questions/447408

  •  22-07-2019
  •  | 
  •  

سؤال

وهذا الرمز بتصنيف:

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

وإذا اعتقدت (booleanExpression == صحيح) كان من المفترض أن يكون التكرار. لماذا ليس هو في هذه الحالة؟

هل كانت مفيدة؟

المحلول

وليس هناك التحويل الضمني من Nullable<bool> إلى bool. هناك <م> هو والتحويل الضمني من bool إلى Nullable<bool> وهذا ما يحدث (من حيث اللغة) إلى كل من الثوابت منطقي في النسخة الأولى. ثم يتم تطبيق مشغل bool operator==(Nullable<bool>, Nullable<bool>. (هذه ليست هي نفس مشغلي رفعت أخرى - والنتيجة هي مجرد bool، وليس Nullable<bool>)

في بعبارة أخرى، فإن تعبير "فريد == كاذبة" من نوع bool، في حين أن التعبير "فريد" هو من نوع Nullable<bool> بالتالي لا يمكنك استخدامه بمثابة "لو" التعبير.

وتحرير: للرد على التعليقات، هناك أبدا التحويل الضمني من Nullable<T> إلى T لسبب وجيه - يجب أن تحويلات ضمنية لا رمي الاستثناءات، وإلا إذا كنت تريد null لتحويلها ضمنيا إلى default(T) ليس هناك الكثير آخر يمكن أن ينبغي القيام به.

وأيضا، إذا كان هناك <م> كان تحويلات ضمنية في كلا الاتجاهين الجولة، تعبيرا مثل "قيم الفارغة + nonNullable" سيكون مربكا للغاية (لأنواع التي تدعم +، مثل int). على حد سواء + (؟ T ؟، T) و+ (T، T) ستكون متاحة، اعتمادا على المعامل وتحويلها - ولكن النتائج قد تكون مختلفة جدا

وأنا 100٪ وراء هذا القرار أن يكون مجرد تحويل صريح من Nullable<T> إلى T.

نصائح أخرى

ولأن فريد ليس منطقي. هو البنية التي لها خاصية منطقية تسمى ISNULL، أو HasValue، أو أيا كان ... الكائن يدعى فريد هو كائن مركب معقد يحتوي على منطقية وقيمة، وليس منطقي البدائية نفسها ...

وفيما يلي، على سبيل المثال هي الطريقة التي يمكن تنفيذها على قيم الفارغة كثافة العمليات. يتم تطبيق قيم الفارغة عام يكاد يكون من المؤكد بالمثل (ولكن بشكل عام). هنا يمكنك ان ترى كيفية تنفيذ تحويلات ضمنية وصريحة ..

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

ووNullable<bool> == true البيان هو التحقق ضمنا Nullable<bool> == (Nullable<bool>)true.

ملحوظة أن Nullable<bool> نفسها ليست منطقية. وهو المجمع لمنطقية التي يمكن أيضا ان تترك فارغة.

وجاء القضية التنفيذ تماما بقوله: Fred من نوع Nullable<bool> ولم يتم تعريف المشغل ! لNullable<bool>. لا يوجد أي سبب لماذا ينبغي تحديد المشغل ! على Nullable<bool> من حيث bool.

ونقلا عن مايكروسوفت:

<اقتباس فقرة>   

عند إجراء المقارنات مع أنواع nullable، إذا كان أحد   أنواع nullable فارغة، دائما تقييمها مقارنة أنها كاذبة.

والقاعدة لا تقدم أي إشارة إلى التحويل الضمني. انها مجرد اتفاقية التعسفية التي تهدف الى ضمان عدم التعبيرات المنطقية لها استثناءات. وبمجرد أن القاعدة هي في مكان ونحن نعرف كيفية كتابة التعليمات البرمجية. للأسف غاب Microsoft هذا المشغل أحادي. أن تكون متسقة مع سلوك مشغلي ثنائي، يجب أن يكون البرمجية التالية نهاية سعيدة.

لذلك

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

وأراهن أنك هناك المبرمجين التي لديها الآن لكتابة fred==false في حين أن مايكروسوفت حل هذه القضية فارغة على ما يبدو الماضية.

إذا يلقي فريد لالبولي، فإنه سيتم تجميع:

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

وأعتقد أنه عند مقارنة منطقي؟ لمنطقي، المترجم جعل يلقي implicite، لا المقارنة، ومن ثم العودة صحيحة أو خاطئة. النتيجة: التعبير تقييم إلى منطقي

.

عند لا تقارن منطقي؟ إلى شيء، والتعبير تقييم إلى منطقي ؟، من هو غير قانوني هناك.

وتقنيا الاختبار الشرطي عارية لا يتطلب التحويل الضمني لمنطقي إذا كان لديك تنفيذ المشغل الصحيح.

bool? nullableBool = null;
SqlBoolean sqlBoolean = SqlBoolean.Null;
bool plainBool = sqlBoolean; // won't compile, no implicit conversion
if (sqlBoolean) { } // will compile, SqlBoolean implements true operator

وتتطلع السؤال الأصلي لتنفيذ أسلوب SQL من القيم الخالية حيث يتم التعامل باطلا أشبه المجهول، في حين أن تنفيذ قيم الفارغة أكثر مثل إضافة لاغية كقيمة اضافية محتملة. على سبيل المثال قارن:

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top