2016-05-01 10 views
4

いくつかのシナリオでは、メソッドにEnumを渡すときに、単一のEnum値であるかどうかを処理する必要があります。それ以外の場合は、この単純な拡張を記述します。列挙型フラグの組み合わせに含まれるフラグの量を決定するベストプラクティス?

Vb。ネット:

<Extension> 
Public Function FlagCount(ByVal sender As System.[Enum]) As Integer 
    Return sender.ToString().Split(","c).Count() 
End Function 

C#(オンライン翻訳):

[Extension()] 
public int FlagCount(this System.Enum sender) { 
    return sender.ToString().Split(',').Count(); 
} 

使用例:

Vb.Net:

Dim flags As FileAttributes = (FileAttributes.Archive Or FileAttributes.Compressed) 
Dim count As Integer = flags.FlagCount() 
MessageBox.Show(flagCount.ToString()) 

C#(オンライン翻訳):

FileAttributes flags = (FileAttributes.Archive | FileAttributes.Compressed); 
int count = flags.FlagCount(); 
MessageBox.Show(flagCount.ToString()); 

私は現在、Stringとしてフラグの組み合わせを表す避けるためにやっていることが、より直接的かつ効率的な方法が存在する場合、私はちょうどお願いしたいと思いますそれを分割します。

+1

? – Corak

+0

話題外トピック:不要なキーワードと修飾子を省略することで、ソースコードを見やすくすることができます: 'Function FlagCount(ByVal送信者システムとして[Enum])As Integer'を 'あなたがコード化しなければならない限り、VB関数はデフォルトではpublicであり、 'ByVal'は残念ですが、型修飾子は特に' System'のために余分です。(C#とは違い、関数のFlagCount([Enum] As) Visual Studio 2010またはそれ以前) – miroxlav

+0

@miroxlavあなたの提案を感謝しますが、私は逆に、Vb.Netのデフォルトの意味は開発者によって無視されるべきではないことを意味します。これは悪い習慣ではありません。コードに 'ByRef'を持つparamsと' ByVal'を持たないparamsが含まれていると読みにくくなります。一方、私は 'System'名前空間の仕様について完全に同意しますが、実際のソースコードでは拡張機能を含むモジュールの名前が' Enum'という名前になっているので、 'System '曖昧さ回避を避けるための名前空間。 – ElektroStudios

答えて

6

オプションA:

public int FlagCount(System.Enum sender) 
{ 
    bool hasFlagAttribute = sender.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0; 
    if (!hasFlagAttribute) // No flag attribute. This is a single value. 
     return 1; 

    var resultString = Convert.ToString(Convert.ToInt32(sender), 2); 
    var count = resultString.Count(b=> b == '1');//each "1" represents an enum flag. 
    return count; 
} 

説明:列挙型は "フラグ属性を" 持っていない場合、単一の値にバインドされて

  • enumに "Flags"属性がある場合は、それをビット表現に変換し、 "1"を数えます。各「1」は列挙フラグを表す。

オプションB:

  1. はすべてflagedのアイテムを取得します。
  2. コード...

それらを数:

public int FlagCount(this System.Enum sender) 
{ 
    return sender.GetFlaggedValues().Count; 
} 

/// <summary> 
/// All of the values of enumeration that are represented by specified value. 
/// If it is not a flag, the value will be the only value returned 
/// </summary> 
/// <param name="value">The value.</param> 
/// <returns></returns> 
public static List<Enum> GetFlaggedValues(this Enum value) 
{ 
    //checking if this string is a flagged Enum 
    Type enumType = value.GetType(); 
    object[] attributes = enumType.GetCustomAttributes(true); 

    bool hasFlags = enumType.GetCustomAttributes(true).Any(attr => attr is System.FlagsAttribute); 
    //If it is a flag, add all flagged values 
    List<Enum> values = new List<Enum>(); 
    if (hasFlags) 
    { 
     Array allValues = Enum.GetValues(enumType); 
     foreach (Enum currValue in allValues) 
     { 
      if (value.HasFlag(currValue)) 
      { 
       values.Add(currValue); 
      } 
     } 
    } 
    else//if not just add current value 
    { 
     values.Add(value); 
    } 
    return values; 
} 
+0

答えていただきありがとうございますが、オプションAがToInt64関数を使用していても、一部の(U)Int64列挙型の算術オーバーフローを生成できるかどうかは疑問です。 – ElektroStudios

+0

オプションBは、LINQ、リスト、配列を使用しているため、文字列分割よりも非常に高価です。私の現在のコードを改善する代替手段を探しています(リファクタリングできると思います)。もっと簡単に効率を上げて)、存在するすべての種類の選択肢を発見するのではなく(それもそれを知っているのは良いですし、私はそれを感謝しますが、私が求めているものではありません)すべてのシナリオで期待される結果が得られれば – ElektroStudios

+1

@ElektroStudios可能性のあるオーバーフローについては正しいですが、修正するのは簡単です(たとえば、基になるタイプをチェックしてから変換するなど)。オプションBはもっと高価かもしれませんが、私はそれがあなたに特定のアプリケーションにどれだけ影響を与えるかをチェックする価値があると思います。私のために、私は 'GetFlaggedValues'が非常に有益であることを発見しました... –

0

は、この1つは手放すことができませんでした。整数のビットを数えるときのベストプラクティスは文字列に変換されません... 私たちはすべて高級言語を使用するようになりました。 ;)

質問が最も効率的な実装に関するものだったので、ここで私の答えです。私はそれをハイパー最適化しようとしていないので、私はそれを混乱させると思います。私は比較を簡単にするために、以前の答えをベースとして使用しました。 フラグをカウントする方法と、フラグが1つしかないかどうかを知りたい場合に早期に終了する方法の2つがあります。 注意:標準の非フラグ列挙型は任意の数値でもかまいませんので、フラグ属性チェックを削除することはできません。どのように `Enum.GetValues(typeof演算(YourEnum))。OfType ().Count(enumValue => yourValue.HasFlag(enumValue))`について

public static int FlagCount(this System.Enum enumValue){ 
     var hasFlagAttribute = enumValue.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0; 
     if (!hasFlagAttribute) 
      return 1; 
     var count = 0; 
     var value = Convert.ToInt32(enumValue); 
     while (value != 0){ 
      if ((value & 1) == 1) 
       count++; 
      value >>= 1; 
     } 
     return count; 
    } 
    public static bool IsSingleFlagCount(this System.Enum enumValue){ 
     var hasFlagAttribute = enumValue.GetType().GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0; 
     if (!hasFlagAttribute) 
      return true; 
     var isCounted = false; 
     var value = Convert.ToInt32(enumValue); 
     while (value != 0){ 
      if ((value & 1) == 1){ 
       if (isCounted) 
        return false; 
       isCounted = true; 
      } 
      value >>= 1; 
     } 
     return true; 
    } 
関連する問題