2012-02-15 34 views
5

Tôi tình cờ sử dụng toán tử cộng (+) trong định nghĩa enum ngày hôm nay, tôi đã rất ngạc nhiên khi thấy các kiểm tra đi kèm đi qua. Bất cứ ai có bất cứ ý tưởng nơi này có thể được tài liệu?Toán tử cộng trong định nghĩa enum

public enum ApprovalItemState 
{ 
    Enqueued = 1, 
    Approved = 2, 
    Denied = 4, 
    Acknowledged = 8, 
    ApprovalAcknowledged = ApprovalItemState.Approved + ApprovalItemState.Acknowledged, 
    DenialAcknowledged = ApprovalItemState.Denied + ApprovalItemState.Acknowledged 
} 


[TestClass] 
public class ApprovalItemStateTests 
{ 
    [TestMethod] 
    public void AreFlagsDeniedAndAcknowledged() 
    { 
     Assert.AreEqual(ApprovalItemState.DenialAcknowledged, ApprovalItemState.Denied | ApprovalItemState.Acknowledged); 
    } 

    [TestMethod] 
    public void IsDenialAcknowledged() 
    { 
     Assert.IsTrue(Enum.IsDefined(typeof(ApprovalItemState), ApprovalItemState.Denied | ApprovalItemState.Acknowledged)); 
     Assert.AreEqual(ApprovalItemState.Denied | ApprovalItemState.Acknowledged, (ApprovalItemState)Enum.Parse(typeof(ApprovalItemState), "DenialAcknowledged")); 
    } 


    [TestMethod] 
    public void IsNotDeniedAndApproved() 
    { 
     Assert.IsFalse(Enum.IsDefined(typeof(ApprovalItemState), ApprovalItemState.Approved | ApprovalItemState.Denied)); 
    } 
} 
+7

Đó là vì giá trị enum (mặc định) chỉ đơn giản là giá trị Int32. Sẽ tốt hơn nếu bộ mã hóa được sử dụng | (bit OR) thay vào đó, tôi nghĩ vậy. –

+0

@DanielPratt Đã phát hiện ra một chút, cũng có thể được đăng dưới dạng câu trả lời. :) –

+0

Tôi nghĩ bạn nên sử dụng bitwise HOẶC thay vào đó, nếu bạn muốn sử dụng enum này làm cờ thì điều này có thể hữu ích: http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx – 0lukasz0

Trả lời

10

C# Ngôn ngữ Spec, trong 14,5, khẳng định:

các nhà khai thác sau đây có thể được sử dụng trên các giá trị của các loại enum:! ==, =, <,>, < =,> = (§ 7.10.5), nhị phân + (§7.8.4), nhị phân - (§7.8.5), ^, &, | (§7.11.2), ~ (§7.7.4), ++ và - (§7.6.9 và §.7.7.5).

Về cơ bản, vì enum được lưu trữ nội bộ dưới dạng Int32 (đó là mặc định, trừ khi bạn chỉ định loại lưu trữ khác), bạn có thể sử dụng phần bổ sung như thế này.

Tuy nhiên, việc sử dụng | phổ biến hơn thay vì + để xác định mặt nạ. Ngoài ra, nó sẽ là phổ biến để bao gồm [Flags] nếu bạn sẽ sử dụng điều này như là một điều tra cờ.

+0

I nghĩ rằng '[Flags] 'không được sử dụng bởi vì một số bang sẽ không hợp lý về mặt kỹ thuật. – Dave

+1

@Dave: Đó là một lý do khủng khiếp để không sử dụng thuộc tính Flags. –

+0

@MarkByers Chăm sóc để xây dựng? – Dave

2

Từ the C# reference on enum:

... Mỗi kiểu enumeration có một loại cơ bản, mà có thể là bất kỳ loại không thể thiếu ngoại trừ char. Giá trị mặc định loại tiềm ẩn các yếu tố liệt kê là int ...

Bằng cách này, nó là thành ngữ hơn (và ít bị lỗi) để sử dụng | thay vì + để kết hợp các giá trị cờ enum. Ví dụ, sai lầm này sẽ không gây ra một vấn đề:

DenialAcknowledged = 
    ApprovalItemState.Denied 
    | ApprovalItemState.Acknowledged 
    | ApprovalItemState.Denied 

Nhưng sai lầm này sẽ gây ra một vấn đề:

DenialAcknowledged = 
    ApprovalItemState.Denied 
    + ApprovalItemState.Acknowledged 
    + ApprovalItemState.Denied 
0

Nó không đáng ngạc nhiên - sự đếm được đại diện bởi các loại không thể thiếu. Bạn cũng có thể sử dụng các toán tử khác, mặc dù nếu bạn sử dụng cờ (ví dụ này đang làm), tốt hơn bạn nên sử dụng thuộc tính [Flags] để xác định chúng và tốt hơn để đặt các bit rõ ràng hơn:

[Flags] 
public enum ApprovalItemState 
{ 
    Enqueued = 1 << 0, 
    Approved = 1 << 1, 
    Denied = 1 << 2, 
    Acknowledged = 1 << 3, 
    ApprovalAcknowledged = ApprovalItemState.Approved | ApprovalItemState.Acknowledged, 
    DenialAcknowledged = ApprovalItemState.Denied | ApprovalItemState.Acknowledged 
} 
1

Approved + Acknowledged chỉ là một hằng số để nó có thể được chỉ định làm giá trị cho phần tử enum. kiểm tra Về - họ làm việc vì int giá trị là "người hạnh phúc", do đó (a + b) == (a | b)

Tuy nhiên nếu thay đổi của bạn rằng một cái gì đó như thế:

public enum ApprovalItemState 
{ 
    Enqueued = 1, 
    Approved = 2, 
    Denied = 7, 
    Acknowledged = 18, 
    ApprovalAcknowledged = Approved + Acknowledged, 
    DenialAcknowledged = Denied + Acknowledged 
} 

và kiểm tra sẽ không vượt qua.

0

Tôi sẽ chia nhỏ một trong số này cho bạn.

DenialAcknowledged = ApprovalItemState.Denied + ApprovalItemState.Acknowledged 
DenialAcknowledged = 4 + 8 
DenialAcknowledged = 12 

Đối với thử nghiệm này:

[TestMethod] 
public void AreFlagsDeniedAndAcknowledged() 
{ 
    Assert.AreEqual(ApprovalItemState.DenialAcknowledged, ApprovalItemState.Denied | ApprovalItemState.Acknowledged); 
} 

Bạn đang kiểm tra:

ApprovalItemState.DenialAcknowledged == ApprovalItemState.Denied | ApprovalItemState.Acknowledged 
12 == 4 | 8 
12 == 0100 | 1000 //bitwise operation 
12 == 1100 
12 == 12 //convert from binary to decimal 

Và đó là lý do tại sao vượt qua bài kiểm tra. Không chính xác đơn giản bằng cách xem mã.

11

Câu trả lời của Reed dĩ nhiên là chính xác. Tôi chỉ nghĩ rằng tôi muốn thêm một chút thú vị của đố. Trước tiên, khi bạn là bên trong enum, tất cả các thành viên của enum đều nằm trong phạm vi. Đây là tình huống duy nhất trong C# trong đó bạn có thể sử dụng một thành viên enum thông qua tên không đủ tiêu chuẩn của nó!

public enum ApprovalItemState 
{ 
    Enqueued = 1, 
    Approved = 2, 
    Denied = 4, 
    Acknowledged = 8, 
    ApprovalAcknowledged = Approved | Acknowledged, 
    DenialAcknowledged = Denied | Acknowledged 
} 

Điểm đố thứ hai là các biên dịch C# thực sự cho phép enum số học liên quan đến enums khác bên trong một enum!

enum E 
{ 
    E1 
} 
enum F 
{ 
    F1 
} 
enum G 
{ 
    G1 = E.E1 + F.F1 
} 

Thông thường sẽ không hợp pháp; bạn không thể thêm hai enums tương tự với nhau và bạn không thể gán kết quả. Trình biên dịch giải phóng các quy tắc đó trong bộ khởi tạo enum để bạn có thể thực hiện những việc như:

enum MyFlags 
{ 
    MyReadOnly = FileFlags.ReadOnly, 
    ... 
Các vấn đề liên quan