2010-01-25 28 views
6

Tôi hiểu làm thế nào Enums làm việc trong C#, và tôi nhận được những gì các thuộc tính Flags mang đến cho bảng.Có nhiều cách để xác định C# Enums với thuộc tính [Flags]?

Tôi đã thấy câu hỏi này, here. Đề xuất hương vị đầu tiên, nhưng không cung cấp bất kỳ lý do/biện minh nào cho nó.

Có sự khác biệt nào trong cách thức hai yếu tố này được xác định hay không, liệu có tốt hơn cách khác không? Những lợi thế để sử dụng synax đầu tiên thay vì thứ hai là gì? Tôi đã luôn luôn sử dụng hương vị thứ hai khi xác định Flags loại Enums ... tôi đã làm điều đó sai tất cả thời gian này?

[Serializable] 
[Flags] 
public enum SiteRoles 
{ 
    User = 1 << 0, 
    Admin = 1 << 1, 
    Helpdesk = 1 << 2 
} 

Có phải đó là không giống như

[Serializable] 
[Flags] 
public enum SiteRoles 
{ 
    User = 1, 
    Admin = 2, 
    Helpdesk = 4 
} 
+0

Mã IL được tạo cho 2 đoạn mã này giống nhau. –

+3

Phát hiện lỗi trong mã này: BackupOperator = 1073714824. Bạn có thể tránh lỗi ở nơi đầu tiên bằng cách nói BackupOperator = 1 << 30 –

+0

Cảm ơn tất cả thông tin, tôi sẽ sử dụng aproach đầu tiên, vì nó có vẻ tốt hơn cho tất cả trừ những trường hợp đơn giản nhất. – Nate

Trả lời

6

Lợi thế chính với ưu tiên đầu tiên là bạn không cần phải tính các giá trị chính xác cho mỗi cờ vì trình biên dịch sẽ làm điều đó cho bạn. Ngoài ra họ cũng giống nhau.

+0

Vậy về cơ bản nó là một thủ thuật biên dịch? – Nate

+2

Có, 1 << n là hằng số để trình biên dịch tính toán nó có thể ít lỗi hơn 1,2,4,8 ... Bạn cũng có thể sử dụng hex ví dụ: 0x1, 0x10, 0x100 ... – Lee

+1

Mặc dù bạn có thể quan tâm nhiều hơn đến các giá trị hex như 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80. –

0

AFAIK nó một cuộc tranh luận có thể đọc. Một số người sẽ nói rằng người đầu tiên dễ đọc hơn vì bạn có chỉ mục thực tế của lá cờ ở phía bên tay phải của '< <'.

+0

Đây có phải là một mẹo biên dịch hiệu quả không? Từ 1 << 2 = 4? – Nate

+1

Nó không phải là một trình biên dịch lừa. Sự khác biệt giữa Helpdesk = 1 << 2, Helpdesk = 4 hoặc Helpdesk = 3 + 1. Nó chỉ là một biểu thức được đánh giá. – empi

+0

Tôi đoán tôi thấy rằng khi tận dụng lợi thế của trình biên dịch, và do đó một thủ thuật biên dịch. Điểm của bạn được thực hiện tốt. – Nate

6

Hãy xem xét các mẫu phức tạp hơn:

[Flags] 
public enum SiteRoles 
{ 
    User = 1 << 12, 
    Admin = 1 << 13, 
    Helpdesk = 1 << 15, 
    AdvancedUser = User | Helpdesk, //or (1<<12)|(1<<13) 
} 

[Flags] 
public enum SiteRoles 
{ 
    User = 4096, //not so obvious! 
    Admin = 8192, 
    Helpdesk = 16384, 
    AdvancedUser = 12288, //! 
} 

[Flags] 
public enum SiteRoles 
{ 
    User = 0x1000, //we can use hexademical digits 
    Admin = 0x2000, 
    Helpdesk = 0x4000, 
    AdvancedUser = 0x3000, //it much simpler calculate binary operator OR with hexademicals 
} 

mẫu này cho thấy rằng trong trường hợp phiên bản đầu tiên này là MUCH MORE thể đọc được. Các chữ số thập phân không phải là cách tốt nhất để biểu diễn các hằng số cờ. Và để biết thêm thông tin về các hoạt động bitwise (xem cũng có thể được sử dụng để biểu diễn các hằng số cờ) xem http://en.wikipedia.org/wiki/Bitwise_operation

0

Có một cách khác để làm điều này khá thanh lịch và vì vậy tôi nghĩ mình sẽ chia sẻ điều mà gần đây tôi đã viết. Nó có lợi ích của việc đòi hỏi rất ít toán và vì vậy tôi nghĩ rằng nó ít bị lỗi. Nó rất dễ đọc, IMHO.

[Flags][Serializable] 
public enum ScopeType : int 
{ 
    Unknown = 0, 
    Global = 1, 
    Namespace = Global << 1, 
    Class = Namespace << 1, 
    Struct = Class << 1, 
    Interface = Struct << 1, 
    Enum = Interface << 1, 
    Function = Enum << 1, 
    Property = Function << 1, 
    PropertyGetter = Property << 1, 
    PropertySetter = PropertyGetter << 1, 
    Using = PropertySetter << 1, 
    If = Using << 1, 
    ElseIf = If << 1, 
    Else = ElseIf << 1, 
    Switch = Else << 1, 
    Case = Switch << 1, 
    For = Case << 1, 
    While = For << 1, 
    DoWhile = While << 1, 
    Lambda = DoWhile << 1, 
    Try = Lambda << 1, 
    Catch = Try << 1, 
    Finally = Catch << 1, 
    Initializer = Finally << 1, 
    Checked = Initializer << 1, 
    Unchecked = Checked << 1, 
    Unsafe = Unchecked << 1, 
    Lock = Unsafe << 1, 
    Fixed = Lock << 1, 

    // I can also group flags together using bitwise-OR. 
    PropertyAccessor = PropertyGetter | PropertySetter, 
    TypeDefinition = Class | Struct | Interface | Enum, 
    TryCatchFinally = Try | Catch | Finally, 
    Conditional = If | ElseIf | Else, 
    Branch = Conditional | Case | TryCatchFinally, 
    Loop = For | While | DoWhile 
} 

LƯU Ý: Kể từ khi điều tra kế thừa từ System.Int32, tôi chỉ có thể xác định 32 cờ. Nếu bạn cần nhiều hơn, bạn sẽ phải sử dụng một số nguyên lớn hơn (System.Int64), tạo nhiều hơn một liệt kê và chuỗi chúng lại với nhau, hoặc chỉ tạo một lớp với một loạt các giá trị boolean.

Các vấn đề liên quan