เครื่องหมายตัวหนอน (~) ในนิยาม enum คืออะไร


149

ฉันประหลาดใจเสมอที่แม้หลังจากใช้ C # ตลอดเวลานี้ฉันยังคงสามารถหาสิ่งที่ฉันไม่รู้เกี่ยวกับ ...

ฉันพยายามค้นหาสิ่งนี้ทางอินเทอร์เน็ต แต่การใช้ "~" ในการค้นหาไม่ได้ผลสำหรับฉันเช่นกันและฉันก็ไม่พบสิ่งใดใน MSDN ด้วย (ไม่ต้องบอกว่ามันไม่มี)

ฉันเห็นตัวอย่างโค้ดนี้เมื่อเร็ว ๆ นี้ตัวหนอน (~) หมายถึงอะไร

/// <summary>
/// Enumerates the ways a customer may purchase goods.
/// </summary>
[Flags]
public enum PurchaseMethod
{   
    All = ~0,
    None =  0,
    Cash =  1,
    Check =  2,
    CreditCard =  4
}

ฉันแปลกใจเล็กน้อยที่เห็นมันดังนั้นฉันจึงพยายามรวบรวมมันและมันใช้งานได้ ... แต่ฉันก็ยังไม่รู้ว่ามันหมายถึงอะไร ความช่วยเหลือใด ๆ ??


4
นี่เป็นทางออกที่ยอดเยี่ยมและสง่างามช่วยให้การอัพเกรด Enum เป็นไปอย่างราบรื่นตลอดเวลา แต่น่าเสียดายที่มันขัดแย้งกับ CA-2217 และจะโยนความผิดพลาดถ้าคุณใช้การวิเคราะห์รหัส :( msdn.microsoft.com/en-us/library/ms182335.aspx
เจสันคอยน์

ตอนนี้ในปี 2020 และฉันพบว่าตัวเองกำลังคิดคำเดียวกับที่คุณเริ่มโพสต์ ดีใจที่ได้ยินว่าฉันไม่ได้อยู่คนเดียว
funkymushroom

คำตอบ:


136

~ เป็นโอเปอเรเตอร์เสริมของเอกนารี - มันพลิกบิตของตัวถูกดำเนินการ

~0 = 0xFFFFFFFF = -1

ในสองส่วนเลขคณิต ~x == -x-1

ผู้ประกอบการ ~ สามารถพบได้ในภาษาใด ๆ ที่ยืมไวยากรณ์จาก C รวมถึง Objective-C / C ++ / C # / Java / Javascript


มันเท่ห์มาก ฉันไม่ได้ตระหนักว่าคุณสามารถทำเช่นนั้นได้ใน enum จะใช้ในอนาคตแน่นอน
Orion Edwards

ดังนั้นมันจึงเทียบเท่ากับ All = Int32.MaxValue? หรือ UInt32.MaxValue
Joel Mueller

2
ทั้งหมด = (int ที่ไม่ได้ลงชื่อ) -1 == UInt32.MaxValue Int32.MaxValue ไม่มีความเกี่ยวข้อง
Jimmy

4
@ Stevo3000: Int32.MinValue คือ 0xF0000000 ซึ่งไม่ใช่ ~ 0 (อันที่จริงแล้ว ~ Int32.MaxValue)
จิมมี่

2
@Jimmy: Int32.MinValue คือ 0x80000000 มีเพียงชุดบิตเดียว (ไม่ใช่สี่ที่ F จะให้คุณ)
ILMTitan

59

ฉันคิดว่า:

[Flags]
public enum PurchaseMethod
{
    None = 0,
    Cash = 1,
    Check = 2,
    CreditCard = 4,
    All = Cash | Check | CreditCard
 }

จะมีความชัดเจนมากขึ้น


10
มันเป็นอย่างแน่นอน ผลกระทบที่ดีเพียงอย่างเดียวของเอกภาพคือถ้ามีใครเพิ่มเข้าไปในการแจงนับ ถึงกระนั้นผลประโยชน์ก็ไม่ได้เกินดุลที่ขาดความชัดเจน
ctacke

12
ฉันไม่เห็นความชัดเจนมากขึ้น มันเพิ่มความซ้ำซ้อนหรือความกำกวม: "ทั้งหมด" หมายถึง "ชุดของทั้ง 3" หรือ "ทุกอย่างใน enum นี้" หรือไม่? หากฉันเพิ่มค่าใหม่ฉันควรเพิ่มลงในทั้งหมดหรือไม่ หากฉันเห็นคนอื่นไม่ได้เพิ่มคุณค่าใหม่ให้กับทุกคนนั่นคือความตั้งใจหรือไม่? ~ 0 ชัดเจน
Ken

16
ความชอบส่วนบุคคลถ้าความหมายของ ~ 0 นั้นชัดเจนต่อ OP เหมือนกับคุณและฉันเขาจะไม่ตั้งคำถามนี้ตั้งแต่แรก ฉันไม่แน่ใจว่าสิ่งที่พูดเกี่ยวกับความชัดเจนของวิธีการหนึ่งเมื่อเทียบกับวิธีอื่น
ฌอน Bright

9
เนื่องจากโปรแกรมเมอร์บางคนที่ใช้ C # อาจไม่รู้ว่า << หมายความว่าอย่างไรเราควรเขียนโค้ดนั้นเพื่อความชัดเจนมากขึ้นหรือไม่ ผมคิดว่าไม่.
Kurt Koller

4
@ พอลมันช่างบ้าคลั่ง หยุดใช้กันเถอะ ในภาษาอังกฤษเพราะหลายคนไม่เข้าใจการใช้งาน หรือคำทั้งหมดที่พวกเขาไม่รู้ ว้าวผู้ประกอบการขนาดเล็กเช่นนี้และเราควรจะทิ้งรหัสของเราไว้สำหรับคนที่ไม่รู้ว่าบิตคืออะไรและจะจัดการกับมันอย่างไร
Kurt Koller

22
public enum PurchaseMethod
{   
    All = ~0, // all bits of All are 1. the ~ operator just inverts bits
    None =  0,
    Cash =  1,
    Check =  2,
    CreditCard =  4
}

เนื่องจากส่วนประกอบสองตัวใน C # ~0 == -1จำนวนที่บิตทั้งหมดเป็น 1 ในการแทนแบบไบนารี่


ดูเหมือนว่าพวกเขากำลังสร้างการตั้งค่าสถานะบิตสำหรับวิธีการชำระเงิน: 000 = ไม่มี; 001 = เงินสด 010 = ตรวจสอบ; 100 = บัตรเครดิต; 111 = ทั้งหมด
Dillie-O

มันไม่ใช่ส่วนประกอบสองอย่างที่กลับด้านทั้งหมดและเพิ่มหนึ่งส่วนดังนั้นส่วนประกอบทั้งสองของ 0 ยังคงเป็น 0 0 ~ เพียงแค่แปลงบิตทั้งหมดหรือส่วนประกอบหนึ่งส่วน
Beardo

ไม่การเติมเต็มสองของมันแค่แปลงบิตทั้งหมด
กำหนดค่า

2
@configurator - ไม่ถูกต้อง ส่วนประกอบที่สมบูรณ์คือการกลับกันของบิต
Dave Markle

c # ใช้สองส่วนประกอบเพื่อแสดงค่าลบ แน่นอน ~ ไม่ใช่สองส่วนประกอบ แต่เพียงแปลงกลับเป็นบิตทั้งหมด ฉันไม่แน่ใจว่าคุณได้รับจากที่ใด Beardo
Johannes Schaub - litb

17

มันดีกว่า

All = Cash | Check | CreditCard

โซลูชันเพราะถ้าคุณเพิ่มวิธีอื่นในภายหลังให้พูดว่า:

PayPal = 8 ,

คุณจะทำกับ tilde-All เรียบร้อยแล้ว แต่ต้องเปลี่ยน all-line ทั้งหมด ดังนั้นจึงเกิดข้อผิดพลาดน้อยลงในภายหลัง

ความนับถือ


มันจะดีกว่าถ้าคุณบอกว่าทำไมมันถึงมีข้อผิดพลาดน้อยกว่า ไลค์: ถ้าคุณเก็บค่าไว้ในฐานข้อมูล / ไฟล์ไบนารี่แล้วเพิ่มแฟล็กอีกอันลงในการแจงนับมันจะรวมอยู่ใน 'ทั้งหมด' ซึ่งหมายความว่า 'ทั้งหมด' จะหมายถึงทั้งหมดเสมอและไม่ใช่แค่ตราบใดที่ ธงเหมือนกัน :)
Aidiakapi

11

เพียงบันทึกด้านข้างเมื่อคุณใช้

All = Cash | Check | CreditCard

คุณมีสิทธิประโยชน์เพิ่มเติมที่Cash | Check | CreditCardจะประเมินAllและไม่ใช่ค่าอื่น (-1) ที่ไม่เท่ากับทั้งหมดในขณะที่มีค่าทั้งหมด ตัวอย่างเช่นหากคุณใช้ช่องทำเครื่องหมายสามช่องใน UI

[] Cash
[] Check
[] CreditCard

และรวมค่าของพวกเขาและผู้ใช้เลือกพวกเขาทั้งหมดคุณจะเห็นAllในผลลัพธ์ enum


นั่นเป็นเหตุผลที่คุณใช้myEnum.HasFlag()แทน: D
Pyritie

@Pyritie: ความคิดเห็นของคุณมีส่วนเกี่ยวข้องกับสิ่งที่ฉันพูดอย่างไร
กำหนดค่า

เช่นเดียวกับใน ... หากคุณใช้ ~ 0 สำหรับ "ทั้งหมด" คุณสามารถทำสิ่งที่ชอบAll.HasFlag(Cash | Check | CreditCard)และนั่นจะทำให้เป็นจริง จะเป็นวิธีแก้ปัญหาเนื่องจาก==ไม่ได้ทำงานกับ ~ 0 เสมอ
Pyritie

โอ้ผมได้พูดคุยเกี่ยวกับสิ่งที่คุณเห็นในการดีบักและมีToString- == Allไม่ได้เกี่ยวกับการใช้
ปรับแต่งค่า

9

สำหรับคนอื่นที่พบว่าคำถามนี้ให้ความกระจ่างฉันมี~ตัวอย่างรวดเร็วที่จะแบ่งปัน ตัวอย่างต่อไปนี้จากการใช้วิธีการทาสีดังรายละเอียดในเอกสาร Mono นี้ใช้~เพื่อผลที่ยอดเยี่ยม:

PaintCells (clipBounds, 
    DataGridViewPaintParts.All & ~DataGridViewPaintParts.SelectionBackground);

หากไม่มี~โอเปอเรเตอร์รหัสอาจมีลักษณะดังนี้:

PaintCells (clipBounds, DataGridViewPaintParts.Background 
    | DataGridViewPaintParts.Border
    | DataGridViewPaintParts.ContentBackground
    | DataGridViewPaintParts.ContentForeground
    | DataGridViewPaintParts.ErrorIcon
    | DataGridViewPaintParts.Focus);

... เนื่องจากการแจงนับมีลักษณะดังนี้:

public enum DataGridViewPaintParts
{
    None = 0,
    Background = 1,
    Border = 2,
    ContentBackground = 4,
    ContentForeground = 8,
    ErrorIcon = 16,
    Focus = 32,
    SelectionBackground = 64,
    All = 127 // which is equal to Background | Border | ... | Focus
}

สังเกตเห็นความคล้ายคลึงกันของ enum นี้กับคำตอบของ Sean Bright หรือไม่?

ฉันคิดว่าสิ่งที่สำคัญที่สุดสำหรับฉันคือมัน~เป็นโอเปอเรเตอร์ตัวเดียวกันใน enum เพราะมันอยู่ในบรรทัดรหัสปกติ


ในบล็อกรหัสที่สองของคุณไม่ควร&เป็น|s หรือไม่?
ClickRick

@ClickRick ขอบคุณสำหรับการจับ ตอนนี้การบล็อกโค้ดที่สองนั้นสมเหตุสมผลแล้ว
Mike

5

มันเป็นโอเปอเรเตอร์เสริมนี่คือบทความที่ฉันมักจะอ้างถึงสำหรับผู้ประกอบการระดับบิต

http://www.blackwasp.co.uk/CSharpLogicalBitwiseOps.aspx

msdn ใช้มันในบทความ enums ด้วยซึ่งแสดงให้เห็นว่ามันใช้งานได้ดีขึ้น

http://msdn.microsoft.com/en-us/library/cc138362.aspx


1

ทางเลือกที่ฉันใช้เป็นการส่วนตัวซึ่งทำสิ่งเดียวกันกับคำตอบของ @Sean Bright แต่ดูดีกว่าสำหรับฉันนั่นคือ:

[Flags]
public enum PurchaseMethod
{
    None = 0,
    Cash = 1,
    Check = 2,
    CreditCard = 4,
    PayPal = 8,
    BitCoin = 16,
    All = Cash + Check + CreditCard + PayPal + BitCoin
}

(a + b + c) == (a | b | c)แจ้งให้ทราบว่าธรรมชาติไบนารีของตัวเลขเหล่านั้นซึ่งมีอำนาจทั้งหมดของทั้งสองทำให้ยืนยันต่อไปนี้เป็นจริง: และ IMHO +ดูดีขึ้น


1

ฉันได้ทดลองกับ ~ และพบว่ามันอาจมีข้อผิดพลาด พิจารณาตัวอย่างนี้สำหรับ LINQPad ซึ่งแสดงว่าค่า enum ทั้งหมดไม่ทำงานตามที่คาดไว้เมื่อค่าทั้งหมดถูกรวมเข้าด้วยกัน

void Main()
{
    StatusFilterEnum x = StatusFilterEnum.Standard | StatusFilterEnum.Saved;
    bool isAll = (x & StatusFilterEnum.All) == StatusFilterEnum.All;
    //isAll is false but the naive user would expect true
    isAll.Dump();
}
[Flags]
public enum StatusFilterEnum {
      Standard =0,
      Saved =1,   
      All = ~0 
}

มาตรฐานไม่ควรรับค่า 0 แต่มีค่ามากกว่า 0
Adrian Iftode

0

เพียงแค่ต้องการเพิ่มถ้าคุณใช้ [สถานะ] enum มันอาจจะสะดวกกว่าถ้าคุณใช้ตัวดำเนินการกะด้านซ้ายแบบ bitwise เช่นนี้

[Flags]
enum SampleEnum
{
    None   = 0,      // 0
    First  = 1 << 0, // 1b    = 1d
    Second = 1 << 1, // 10b   = 2d
    Third  = 1 << 2, // 100b  = 4d
    Fourth = 1 << 3, // 1000b = 8d
    All    = ~0      // 11111111b
}

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