ตัวดำเนินการเท็จใน C # เหมาะสำหรับอะไร?


107

มีตัวดำเนินการแปลก ๆ สองตัวใน C #:

ถ้าฉันเข้าใจถูกต้องตัวดำเนินการเหล่านี้สามารถใช้ในประเภทที่ฉันต้องการใช้แทนนิพจน์บูลีนและฉันไม่ต้องการให้การแปลงโดยนัยเป็นบูล

สมมติว่าฉันมีคลาสต่อไปนี้:

    public class MyType
    {
        public readonly int Value;

        public MyType(int value)
        {
            Value = value;
        }

        public static bool operator true (MyType mt)
        {
            return  mt.Value > 0;
        }

        public static bool operator false (MyType mt)
        {
            return  mt.Value < 0;
        }

    }

ดังนั้นฉันสามารถเขียนโค้ดต่อไปนี้:

    MyType mTrue = new MyType(100);
    MyType mFalse = new MyType(-100);
    MyType mDontKnow = new MyType(0);

    if (mTrue)
    {
         // Do something.
    }

    while (mFalse)
    {
        // Do something else.
    }

    do
    {
        // Another code comes here.
    } while (mDontKnow)

อย่างไรก็ตามสำหรับตัวอย่างทั้งหมดข้างต้นจะดำเนินการตัวดำเนินการที่แท้จริงเท่านั้น แล้วตัวดำเนินการเท็จใน C # มีไว้เพื่ออะไร?

หมายเหตุ: ตัวอย่างเพิ่มเติมสามารถพบได้ที่นี่ , ที่นี่และที่นี่


สามารถดูเอกสารสมัยใหม่ได้ที่ docs.microsoft.com/en-us/dotnet/csharp/language-reference/... เอกสารแนะนำว่าไม่มีเหตุผลที่จะกำหนดตัวดำเนินการนี้อีกต่อไปเนื่องจาก C # 2.0 ได้เพิ่มประเภท nullable
Mark Amery

คำตอบ:


65

คุณสามารถใช้เพื่อลบล้างตัวดำเนินการ&&และ||

&&และ||ผู้ประกอบการไม่สามารถแทนที่ แต่ถ้าคุณแทนที่|, &, trueและfalseในตรงทางที่ถูกคอมไพเลอร์จะเรียก|และ&เมื่อคุณเขียนและ||&&

ตัวอย่างเช่นดูรหัสนี้ (จากhttp://ayende.com/blog/1574/nhibernate-criteria-api-operator-overloading - ที่ฉันพบเกี่ยวกับเคล็ดลับนี้เวอร์ชันที่เก็บถาวรโดย @BiggsTRC):

public static AbstractCriterion operator &(AbstractCriterion lhs, AbstractCriterion rhs)
{
       return new AndExpression(lhs, rhs);
}

public static AbstractCriterion operator |(AbstractCriterion lhs, AbstractCriterion rhs)
{
       return new OrExpression(lhs, rhs);
}

public static bool operator false(AbstractCriterion criteria)
{
       return false;
}
public static bool operator true(AbstractCriterion criteria)
{
       return false;
}

เห็นได้ชัดว่านี่เป็นผลข้างเคียงและไม่ใช่วิธีที่ตั้งใจจะใช้ แต่มีประโยชน์


ลิงค์ของคุณคือ 404 ไม่แน่ใจว่าคุณต้องการแก้ไขอย่างไรฉันจึงปล่อยไว้
user7116

ฉันอัปเดต URL ด้วยสำเนาที่เก็บถาวรเพื่อให้ยังสามารถอ่านได้
IAmTimCorey

25

Shog9 และ Nir: ขอบคุณสำหรับคำตอบ คำตอบเหล่านั้นชี้ให้ฉันดูบทความของ Steve Eichertและมันก็ชี้ให้ฉันไปที่msdn :

การดำเนินการ x && y ถูกประเมินเป็น T. false (x)? x: T. & (x, y) โดยที่ T. false (x) คือการเรียกใช้ตัวดำเนินการที่ประกาศเท็จใน T และ T & (x, y) เป็นการเรียกใช้ตัวดำเนินการที่เลือก &. กล่าวอีกนัยหนึ่ง x จะถูกประเมินก่อนและเรียกใช้ตัวดำเนินการเท็จในผลลัพธ์เพื่อพิจารณาว่า x เป็นเท็จแน่นอน จากนั้นถ้า x เป็นเท็จแน่นอนผลลัพธ์ของการดำเนินการคือค่าที่คำนวณก่อนหน้านี้สำหรับ x มิฉะนั้น y จะถูกประเมินและตัวดำเนินการที่เลือก & ถูกเรียกใช้กับค่าที่คำนวณก่อนหน้านี้สำหรับ x และค่าที่คำนวณสำหรับ y เพื่อสร้างผลลัพธ์ของการดำเนินการ


ฉันสงสัยว่าทำไมพวกเขาถึงไม่เลือกใช้(!T.true(x)) ? x : T.&(x, y)ตรรกะแทน
Des Nerger

14

หน้าที่คุณเชื่อมโยงไปยัง http://msdn.microsoft.com/en-us/library/6x6y6z4d.aspxระบุว่ามีไว้เพื่ออะไรซึ่งเป็นวิธีจัดการบูลที่เป็นโมฆะก่อนที่จะมีการนำประเภทค่าที่เป็นโมฆะมาใช้

ฉันเดาว่าทุกวันนี้พวกเขาดีสำหรับสิ่งต่างๆเช่นเดียวกับ ArrayList นั่นคือไม่มีอะไรแน่นอน


7

AFAIK จะใช้ในการทดสอบเท็จเช่นเมื่อตัว&&ดำเนินการเข้ามาเล่น จำ && การลัดวงจรดังนั้นในนิพจน์

if ( mFalse && mTrue) 
{
   // ... something
}

mFalse.false()ถูกเรียกและเมื่อส่งคืนtrueนิพจน์จะลดลงเป็นการเรียกไปที่ 'mFalse.true ()' (ซึ่งควรจะกลับมาfalseหรือสิ่งต่างๆจะแปลกขึ้น)

ทราบว่าคุณต้องใช้&ประกอบในการสั่งซื้อสำหรับการแสดงออกในการรวบรวมว่าเนื่องจากมันใช้ในกรณีที่ผลตอบแทนmFalse.false()false


3

ดูเหมือนจากบทความ MSDN ที่คุณเชื่อมโยงไปนั้นมีไว้เพื่ออนุญาตให้มีประเภทบูลีนที่เป็นโมฆะก่อนประเภท Nullable (เช่น int?, bool? ฯลฯ ) ที่ถูกแนะนำเป็นภาษาใน C # 2 ดังนั้นคุณจะจัดเก็บค่าภายในที่ระบุว่าค่านั้นเป็นจริงหรือเท็จหรือเป็นโมฆะเช่นในตัวอย่างของคุณ> 0 สำหรับ true <0 สำหรับ false และ == 0 สำหรับ null จากนั้นคุณจะได้รับความหมาย null ในสไตล์ SQL นอกจากนี้คุณยังต้องใช้เมธอดหรือคุณสมบัติ. IsNull เพื่อให้สามารถตรวจสอบความว่างเปล่าได้อย่างชัดเจน

เปรียบเทียบกับ SQL ลองนึกภาพตารางตารางที่มี 3 แถวที่มีค่า Foo ตั้งค่าเป็นจริง 3 แถวที่มีค่า Foo ตั้งค่าเป็นเท็จและ 3 แถวที่มีค่า Foo ตั้งค่าเป็น null

SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE
6

ในการนับแถวทั้งหมดคุณต้องทำสิ่งต่อไปนี้: -

SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE OR Foo IS NULL
9

ไวยากรณ์ 'IS NULL' นี้จะมีรหัสเทียบเท่าในคลาสของคุณเป็น. IsNull ()

LINQ ทำให้การเปรียบเทียบกับ C # ชัดเจนยิ่งขึ้น: -

int totalCount = (from s in MyTypeEnumerable
                 where s || !s
                 select s).Count();

จินตนาการว่า MyTypeEnumberable มีเนื้อหาในฐานข้อมูลเหมือนกันทุกประการคือ 3 ค่าเท่ากับจริง 3 ค่าเท่ากับเท็จและ 3 ค่าเท่ากับ null ในกรณีนี้ totalCount จะประเมินเป็น 6 ในกรณีนี้ อย่างไรก็ตามหากเราเขียนโค้ดใหม่เป็น: -

int totalCount = (from s in MyTypeEnumerable
                 where s || !s || s.IsNull()
                 select s).Count();

จากนั้น totalCount จะประเมินเป็น 9

ตัวอย่าง DBNull ที่ระบุในบทความ MSDN ที่เชื่อมโยงบนตัวดำเนินการเท็จแสดงให้เห็นถึงคลาสใน BCL ซึ่งมีลักษณะการทำงานที่แน่นอนนี้

ผลสรุปคือคุณไม่ควรใช้สิ่งนี้เว้นแต่คุณจะแน่ใจอย่างสมบูรณ์ว่าคุณต้องการพฤติกรรมประเภทนี้จะดีกว่าถ้าใช้ไวยากรณ์ที่ง่ายกว่ามากเท่านั้น !!

อัปเดต:ฉันเพิ่งสังเกตว่าคุณต้องแทนที่ตัวดำเนินการตรรกะด้วยตนเอง!, || และ && เพื่อให้ทำงานได้อย่างถูกต้อง ฉันเชื่อว่าตัวดำเนินการที่เป็นเท็จป้อนเข้าไปในตัวดำเนินการเชิงตรรกะเหล่านี้เช่นการระบุความจริงความเท็จหรือ 'อย่างอื่น' ตามที่ระบุไว้ในความคิดเห็นอื่น! x จะไม่ทำงานกับค้างคาว ต้องโอเวอร์!. ความแปลก!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.