トップ回答者
Bitフラグの扱い

質問
-
お世話になっております。
早速ですが、質問させてください。
現在、VB.netで開発しておりまして下記のような処理があります。
if(a=a) then f_a = True if(b=b) then f_b = True ・・・・ if(g=g) then f_g = True
この後、全てのフラグを見て、
一つでも立っているか、一つも立っていないか等を検出したいのです。
Cで開発していた時は共用体を用い、その1byteにOrしてあげたりと
していましたが、VBとなると調べた結果、BitArrayというのがあるみたいで
使ってみようにも、
検出する際、わざわざByteにコピーしてあげて...
みたいになってしまうのか美しくありません。
見た目ににも、美しく書きやすい
『複数フラグの簡潔判断方法』
が、ありましたらご教示ください。
回答
-
フラグを管理するクラスを作成して、好きなプロパティ、例えば「全てOFFかどうかをBooleanで返す」などを
実装する方法はどうでしょうか。
以下簡単にサンプルを作ってみました。必要な機能はプロパティやメソッドとして追加実装できます。
■使い方
' フラグ数を9個でインスタンスを作成 Dim fa As New FlgArray(9) ' フラグ数を13個で全てONの状態でインスタンスを作成 Dim fa2 As New FlgArray(13, True) ' フラグの0番目と7番目を立てる fa(0) = True fa(7) = True ' フラグの6番目の状態を取得する Dim flg6 As Boolean = fa(6) ' フラグ全てをリセットする fa.AllTo = False ' フラグが全てONかどうか If fa.IsAllOn Then Console.WriteLine("全てON") End If ' フラグが全てOFFかどうか If fa.IsAllOff Then Console.WriteLine("全てOFF") End If ' フラグがひとつでもONかどうか If fa.IsAnyOn Then Console.WriteLine("ひとつでもON") End If
■クラス本体
''' <summary> ''' フラグ管理クラス ''' </summary> ''' <remarks></remarks> Public Class FlgArray ' メンバ Private _flgs As ULong Private _AllOn As ULong = 0UL ' コンストラクタ Public Sub New(ByVal length As Integer) If length > 64 Then Throw New Exception("length over.") End If For i As Integer = 0 To length - 1 _AllOn = _AllOn Or 1UL << i Next End Sub ' コンストラクタ(初期値指定あり) Public Sub New(ByVal length As Integer, ByVal value As Boolean) If length > 64 Then Throw New Exception("length over.") End If For i As Integer = 0 To length - 1 _AllOn = _AllOn Or 1UL << i Next AllTo = value End Sub ' フラグの状態を取得・設定する Default Public Property Flg(ByVal i As Integer) As Boolean Get If (_flgs And 1UL << i) = 1UL << i Then Return True End If Return False End Get Set(ByVal value As Boolean) If value Then _flgs = _flgs Or 1UL << i Else _flgs = _flgs And (_AllOn Xor 1UL << i) End If End Set End Property ' フラグ全ての値を設定する Public WriteOnly Property AllTo() As Boolean Set(ByVal value As Boolean) If value Then _flgs = _AllOn Else _flgs = 0UL End If End Set End Property ' 全てONかどうか Public ReadOnly Property IsAllOn() As Boolean Get If _flgs = _AllOn Then Return True End If Return False End Get End Property ' 全てOFFかどうか Public ReadOnly Property IsAllOff() As Boolean Get If _flgs = 0UL Then Return True End If Return False End Get End Property ' ひとつでもONかどうか Public ReadOnly Property IsAnyOn() As Boolean Get If _flgs > 0UL Then Return True End If Return False End Get End Property End Class
- 回答としてマーク segment 2010年12月15日 6:22
すべての返信
-
複数という時点で、まずフラグの管理はコレクションなり配列で持つ方法がよいかなと思いました。
そして.NETにはLINQというものがありますので、これを利用して書いた場合、以下のように書くことができます。
' Boolean型のフラグデータの配列(BitArrayを利用する場合) Dim ba As New BitArray(New Boolean() {False, False, False, False}) ' 1つ以上フラグがたっているか If (From r In ba Where r Select r).Count() > 0 Then Console.WriteLine("1件以上True") End If ' 全てフラグがたっていないか If (From r In ba Where r Select r).Count() = 0 Then Console.WriteLine("全てFalse") End If ' 全てフラグがたっているか If (From r In ba Where r Select r).Count() = ba.Count Then Console.WriteLine("全てTrue") End If
追記:trapemiyaさんの返信内容と同様です
- 編集済み honefai 2010年12月15日 1:23 送信後気づく(汗
-
ご回答、ありがとうございます!
なるほど、便利そうですが使用するにはFrameworkのバージョンが3.5以上と
なっているようです。
残念ながら、今回の開発には2までで開発しなければならず他の方法があれば
うれしいです><
理想の形:
' マッチングフラグの定義 <StructLayout(LayoutKind.Explicit)> _ Structure DoubleWord <FieldOffset(0)> Public Value As System.UInt32 <FieldOffset(0)> Public f_a As System.Byte <FieldOffset(1)> Public f_b As System.Byte <FieldOffset(2)> Public f_c As System.Byte <FieldOffset(3)> Public f_d As System.Byte End Structure Dim MatchFlag As New DoubleWord() MatchFlag.f_a = 0 MatchFlag.f_b = 1 MatchFlag.f_c = 0 MatchFlag.f_d = 1 ' 1つ以上 If (MatchFlag.Value > 0) Then ’ 処理 End If ' フラグ初期化 MatchFlag.Value = 0
これは、共用体を使った例ですがメモリ範囲をByteでしか設定できまぜん。
というか、こういう思想・設計じたいが.Net的ではないのかもしれませんね。。
-
単純なビット演算ではフラグの数が足りないのですか?
列挙体をビット・フィールドとして取り扱うには?[C#、VB] - @IT
http://www.atmarkit.co.jp/fdotnet/dotnettips/1052enumflags/enumflags.html
# .NET Framework 4 の HasFlags は便利そうですね。(余談ですが) -
フラグを管理するクラスを作成して、好きなプロパティ、例えば「全てOFFかどうかをBooleanで返す」などを
実装する方法はどうでしょうか。
以下簡単にサンプルを作ってみました。必要な機能はプロパティやメソッドとして追加実装できます。
■使い方
' フラグ数を9個でインスタンスを作成 Dim fa As New FlgArray(9) ' フラグ数を13個で全てONの状態でインスタンスを作成 Dim fa2 As New FlgArray(13, True) ' フラグの0番目と7番目を立てる fa(0) = True fa(7) = True ' フラグの6番目の状態を取得する Dim flg6 As Boolean = fa(6) ' フラグ全てをリセットする fa.AllTo = False ' フラグが全てONかどうか If fa.IsAllOn Then Console.WriteLine("全てON") End If ' フラグが全てOFFかどうか If fa.IsAllOff Then Console.WriteLine("全てOFF") End If ' フラグがひとつでもONかどうか If fa.IsAnyOn Then Console.WriteLine("ひとつでもON") End If
■クラス本体
''' <summary> ''' フラグ管理クラス ''' </summary> ''' <remarks></remarks> Public Class FlgArray ' メンバ Private _flgs As ULong Private _AllOn As ULong = 0UL ' コンストラクタ Public Sub New(ByVal length As Integer) If length > 64 Then Throw New Exception("length over.") End If For i As Integer = 0 To length - 1 _AllOn = _AllOn Or 1UL << i Next End Sub ' コンストラクタ(初期値指定あり) Public Sub New(ByVal length As Integer, ByVal value As Boolean) If length > 64 Then Throw New Exception("length over.") End If For i As Integer = 0 To length - 1 _AllOn = _AllOn Or 1UL << i Next AllTo = value End Sub ' フラグの状態を取得・設定する Default Public Property Flg(ByVal i As Integer) As Boolean Get If (_flgs And 1UL << i) = 1UL << i Then Return True End If Return False End Get Set(ByVal value As Boolean) If value Then _flgs = _flgs Or 1UL << i Else _flgs = _flgs And (_AllOn Xor 1UL << i) End If End Set End Property ' フラグ全ての値を設定する Public WriteOnly Property AllTo() As Boolean Set(ByVal value As Boolean) If value Then _flgs = _AllOn Else _flgs = 0UL End If End Set End Property ' 全てONかどうか Public ReadOnly Property IsAllOn() As Boolean Get If _flgs = _AllOn Then Return True End If Return False End Get End Property ' 全てOFFかどうか Public ReadOnly Property IsAllOff() As Boolean Get If _flgs = 0UL Then Return True End If Return False End Get End Property ' ひとつでもONかどうか Public ReadOnly Property IsAnyOn() As Boolean Get If _flgs > 0UL Then Return True End If Return False End Get End Property End Class
- 回答としてマーク segment 2010年12月15日 6:22
-
こんなのもどうでしょうか(^^;
(細かいところは自由に作るって事で)Module Module1
Sub Main()
Dim FL As New Flags(9)
'OFFがあるかを探す
If IsNothing(FL.SearchList(False)) Then
Console.WriteLine("OFFなし")
Else
Console.WriteLine("OFFあり")
End IfFL(5).Value = False
'OFFがあるかを探す
If IsNothing(FL.SearchList(False)) Then
Console.WriteLine("OFFなし")
Else
Console.WriteLine("OFFあり")
End If
Console.ReadLine()End Sub
End Module
Public Class Flag
Property Value As Boolean
Set(ByVal value As Boolean)
_Value = value
End Set
Get
Return _Value
End Get
End Property
Dim _Value As BooleanPublic Sub New(ByVal value As Boolean)
_Value = value
End Sub
End ClassPublic Class Flags
Inherits List(Of Flag)Const _ON As Boolean = True
Const _OFF As Boolean = FalsePublic Sub New(ByVal NumberOfFLag As Integer)
For i As Integer = 0 To NumberOfFLag
Add(New Flag(_ON))
Next
End SubPublic Function SearchList(ByVal value As Boolean) As Flag
Return Me.Find(Function(o) o.Value = value)
End FunctionPublic Sub SetAllValue(ByVal value As Boolean)
For Each x As Flag In Me
x.Value = value
Next
End SubEnd Class
K.Oumi