2012-02-15 96 views
5

我偶然發現今天在枚舉定義中使用了加號(+)運算符,我很驚訝地看到隨附的測試通過。任何人有任何想法可以記錄這些?枚舉定義中的加號運算符

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

這是因爲枚舉值(默認情況下)只是Int32值。如果編碼器使用|會更好(位或),我想。 – 2012-02-15 21:43:41

+0

@DanielPratt充實了一下,不妨將它發佈爲答案。 :) – 2012-02-15 21:45:40

+0

我認爲你應該使用按位或,而如果你想使用這個枚舉作爲標誌,那麼這可能會有所幫助:http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx – 0lukasz0 2012-02-15 21:45:46

回答

10

C#語言規格,在14.5,規定:

以下運算符可以在枚舉類型的值可以使用:!==,=,<,>,< =,> =(§ 7.10.5),二進制+(§7.8.4),二進制 - (§7.8.5),^,&,| (§7.11.2),〜(§7.7.4),++和 - (§7.6.9和§7.7.5)。

基本上,由於枚舉爲Int32內部存儲(這是默認的,除非你指定不同的存儲類型),你可以使用除了這樣。

但是,使用|而不是+來定義掩碼更常見。此外,如果您打算將其用作標誌枚舉,則通常會包含[Flags]

+0

我認爲'[Flags]'沒有被使用,因爲有些州在技術上不合邏輯。 – Dave 2012-02-15 22:08:48

+1

@Dave:這是一個不使用Flags屬性的可怕原因。 – 2012-02-15 22:15:31

+0

@MarkByers謹慎闡述? – Dave 2012-02-15 23:29:22

2

the C# reference on enum

...每個枚舉類型都有一個基本類型,它可以是除焦炭任何整型。 默認基礎類型枚舉元素爲int ...

順便說一句,它是更慣用的(且不易出錯)使用|代替+到枚舉標誌值相結合。例如,這個錯誤不會導致一個問題:

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

但這個錯誤導致一個問題:

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

這並不奇怪 - 枚舉由整型表示。你也可以使用其他的操作符,但是如果你打算使用標誌(這個例子是這樣做的),使用[Flags]屬性來定義它們更好,並且更好地更清楚地設置位:

[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只是一個常量,所以它可以被賦值爲enum元素的值。 關於測試 - 他們的工作,因爲int類型是「快樂的人」,所以(a + b) == (a | b)

但是,如果你的變化,爲類似的東西:

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

和測試將無法通過。

0

我會爲你分解其中之一。

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

對於這個測試:

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

你檢查:

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

正因爲如此,測試通過。通過查看代碼不太直截了當。

11

裏德的答案當然是正確的。我只是認爲我會添加一些有趣的瑣事。首先,當你在裏面的枚舉中,枚舉的所有成員都在範圍內。這是C#中唯一的情況,您可以通過它的非限定名稱使用枚舉成員!

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

第二瑣事的一點是,C#編譯器實際上允許枚舉算術涉及其他枚舉枚舉裏面!

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

通常情況下,這根本不合法;您不能將兩個不同的枚舉添加到一起,並且不能分配結果。編譯器放鬆枚舉初始化器中的這些規則,以便您可以執行下列操作:

enum MyFlags 
{ 
    MyReadOnly = FileFlags.ReadOnly, 
    ...