2012-02-15 18 views
5

今日、列挙型の定義でプラス(+)演算子が使用されていたのを偶然見つけました。誰がこれが文書化されているのか考えている?enum定義のplus演算子

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値であるためです。コーダーが使用されていれば良いでしょう。 (ビットOR)代わりに、私は思う。 –

+0

@DanielPrattちょっと洗練されていて、答えとして投稿されるかもしれません。 :) –

+0

私はあなたがフラグとしてこのenumを使用したい場合、この代わりにbitwise ORを使うべきだと思います。これは参考になるかもしれません:http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx – 0lukasz0

答えて

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)。

基本的に、enumは内部でInt32として保存されています(別のストレージタイプを指定しない限りデフォルトです)。このように追加を使用できます。

しかし、+の代わりに|を使用してマスクを定義するのはずっと一般的です。また、フラグの列挙として使用する場合は、[Flags]を含めることが一般的です。

+0

私いくつかの州は技術的に論理的ではないので、[Flags] 'は使用されていないと考えてください。 – Dave

+1

@Dave:Flags属性を使わないのはひどい理由です。 –

+0

@マークバイヤー精巧にお手入れしますか? – Dave

2

the C# reference on enumから:

...すべての列挙型は、charを除く任意の整数型を指定できます基になる型を持っています。列挙要素のデフォルト根本的なタイプは、(エラーが発生しやすいと少ない)列挙フラグ値を組み合わせること|の代わり+を使用することがより慣用的である、ところで

... int型です。問題が発生します

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

しかし、この間違い:たとえば、この間違いは問題が発生することはありません

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

それは驚くことではありません - 列挙型は整数型で表現されています。他の演算子も使用できますが、フラグを使用する場合(この例では)、[フラグ]属性を使用してビットをより明確にレイアウトする方がはるかに優れています。

[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 

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

をそして、それは、なぜテストパスです:

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

あなたがチェックしています。コードを見るだけではそれほど単純ではありません。

11

リードの答えはもちろん正しいです。私はちょうど私がトリビアの面白いビットを追加すると思った。まず、の中に enumが入っていると、enumのすべてのメンバーが範囲内にあります。これは、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 
} 

通常、これはまったく問題ありません。異なる2つの列挙型を一緒に追加することはできず、結果を割り当てることはできません。コンパイラは、enumイニシャライザ内で以下のようなルールを緩和します。

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