-
区分データ等のソース上の既読性をアップする場合や、間違いを無くする場合に列挙体(Enum)を用います。
列挙体(Enum)の宣言は以下の様になります。 Enum 宣言の中のメンバーは値を指定しなくても、0からの値が割り振られます。 また、メンバーの値を"="イコールで定義すればその値となりますが、それ以降の値の定義されていないものは1加算された値が定義されます。
以下のソースでは、メンバー値を明示的に定義しない場合と、定義した場合の例を示します。列挙体(Enum)の宣言
'メンバ(定数)の値を定義しない場合のEnum Enum TestEnum1 Japan USA China Korea Other End Enum 'メンバ(定数)の値を定義する場合のEnum Enum TestEnum2 Japan = 100 USA China Korea = 1000 Other End EnumTestEnum1 では「Japan」が「0」の値で、以下「USA」「China」「Korea」「Other」は順に「1」「2」「3」「4」の値となります。 また、TestEnum2 では「Japan」が「100」の値で、順に「101」「102」「1000」「1001」の値となります。
実際にプログラムで列挙体(Enum)のメンバー名とその値を列挙する方法を以下に示します。
以下のソースでは、 Enum.GetValues メソッドを用いることで、指定した列挙体に含まれている定数の値の配列が 返されます。 Enum.GetValues メソッドでは指定した値を持つ指定した列挙体にある定数の名前を取得します。
Enumのメンバ名と値を表示
'Enumのメンバ名と値を表示するテスト Private Sub EnumTest_Click(sender As Object, e As EventArgs) Handles EnumTest.Click 'TestEnum1のメンバの値を列挙 Dim Enum1Val As TestEnum1 Dim strMsg As String = "" For Each Enum1Val In [Enum].GetValues(GetType(TestEnum1)) 'メンバ名を取得する Dim strName As String = [Enum].GetName(GetType(TestEnum1), Enum1Val) 'メンバの値と名前を表示する strMsg &= String.Format("{0} = {1}", strName, CInt(Enum1Val)) & vbCrLf Next MsgBox("TestEnum1:" & vbCrLf & strMsg) 'TestEnum2のメンバの値を列挙 Dim Enum2Val As TestEnum1 strMsg = "" For Each Enum2Val In [Enum].GetValues(GetType(TestEnum2)) 'メンバ名を取得する Dim strName As String = [Enum].GetName(GetType(TestEnum2), Enum2Val) 'メンバの値と名前を表示する strMsg &= String.Format("{0} = {1}", strName, CInt(Enum2Val)) & vbCrLf Next MsgBox("TestEnum2:" & vbCrLf & strMsg) Enum2Val = TestEnum2.Other End Sub尚、Enumには同じ値のものを別のメンバー名で定義することが可能ですが、 同じ値のメンバーがある場合は、注意が必要だと思います。 (プログラム上、必要になることもありますので、制限は必要無いとは思います)
列挙体(Enum)の宣言その2
'メンバ(定数)の値を定義する場合のEnum:2 Enum TestEnum2 Japan = 100 USA China Korea = 1000 Other = 1000 '同じ値で「Other」を宣言する End Enum
PR -
クラスや構造体などのオブジェクトのクローンコピーを作りたい場合があります。 各種のオブジェクトのデータを退避する時に、一括でクローンが作れれば便利なのですが、BinaryFormatter クラスを 使って、シリアライズとデシリアライズを行うことでできます。
以下のソースにその関数を記します。 BinaryFormatter の Serialize メソッドによりコピー元のオブジェクトをメモリストリームに展開します。 その後メモリストリームの内容を別のオブジェクトにデシリアライズを行います。ディープコピー関数
''' ----------------------------------------------------------------------- '''''' オブジェクトのコピー ''' '''Type ''' <param name="objSrc">コピー元のオブジェクト</param> '''クローンオブジェクト ''' ----------------------------------------------------------------------- Function DeepCopy(Of T)(ByVal objSrc As T) As T 'クローンオブジェクト宣言 Dim objRet As T 'BinaryFormatterクラス Dim b As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter 'バイト処理を行うメモリストリーム Dim ms As New System.IO.MemoryStream() Try 'シリアライズ(MemoryStreamにシリアライズ化して展開) b.Serialize(ms, objSrc) 'メモリ位置を初期化 ms.Position = 0 'デシリアライズ(MemoryStreamからデシリアライズ化してオブジェクトに戻す) objRet = CType(b.Deserialize(ms), T) Catch ex As Exception ' Finally ms.Close() End Try 'クローンを戻す Return objRet End Functionこの関数を使う例を以下に記します。
以下のソースでは、 DeepCopy 用のテストクラスとして clsCopyTest と、 テスト構造体として structCopyTest を宣言しています。
それぞれのクラス、構造体ともに <Serializable()> を指定しています。 これが無いとシリアライズ処理ができないので注意が必要です。
ディープコピー関数の使用例
'''
''' DeepCopy 用のテストクラス ''' <Serializable()> _ Private Class clsCopyTest Public _strTest As String Public _intTest As Integer 'コンストラクタ Sub New(ByVal strTest As String, ByVal intTest As Integer) Me._strTest = strTest Me._intTest = intTest End Sub '内部データの表示用の文字列取得 Function GetDataString() As String Return "strTest=" & Me._strTest & vbCrLf & "intTest=" & Me._intTest.ToString End Function End Class '''''' DeepCopy 用のテスト構造体 ''' <Serializable()> _ Private Class structCopyTest Private _strTest As String Private _intTest As Integer 'コンストラクタ Sub New(ByVal strTest As String, ByVal intTest As Integer) Me._strTest = strTest Me._intTest = intTest End Sub '内部データの表示用の文字列取得 Function GetDataString() As String Return "strTest=" & Me._strTest & vbCrLf & "intTest=" & Me._intTest.ToString End Function End Class Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'クラスでのテスト Dim clsT As New clsCopyTest("ABCD", 100) 'クラス生成 Dim clsCloneT As clsCopyTest = DeepCopy(clsT) 'クラスクローンコピー clsCloneT._strTest &= "..." 'クローンのデータを更新 clsCloneT._intTest *= 100 'クラスのメソッドで内容表示 MsgBox("Src :" & vbCrLf & clsT.GetDataString & vbCrLf & "Clone:" & vbCrLf & clsCloneT.GetDataString) '構造体でのテスト Dim strucT As New structCopyTest("EFGHI", 200) '構造体生成 Dim strucCloneT As structCopyTest = DeepCopy(strucT) '構造体クローンコピー MsgBox(strucCloneT.GetDataString) '構造体のメソッド End Subボタン処理内でクラスのテストと、構造体のテストを行っています。 クラスの方は、クローンコピーの値を少し変化を加えています。 その後、それぞれのクラス内の値を見てみると、両方の値が異なることが分かります。
関連する記事
⇒クラスのコピーについて(Object.MemberwiseClone)
-
文字列から数値型への変換はいろんな所で必要になりますが、例えばデータベースからのデータの取得で 結果を文字列にして読込んだ場合、これを数値にする場合などです。
数値変換には各データ型の Parse メソッドを利用して可能です。以下に例として Integer型 の変換関数を示します。文字列からInteger型への変換
'''
''' 文字列からInteger型にデータ変換 ''' ''' <param name="strVal">元の文字列</param> '''変換後データ Function StringToInt(ByVal strVal As String) As Integer Try Return Integer.Parse(strVal) '「Convert」クラスの関数を利用しても同じです 'Return Convert.ToInt32(strVal) Catch ex As Exception '例外発生の場合、「0」で返す Return 0 End Try End FunctionParse メソッドでの例外が発生した場合には全て0で返す様にしています。 データベースからのデータ取得で文字列から数値に変換する場合、ほとんど例外エラーは発生しないのでこの様にしています。 データベースの数値カラムからのデータで数値以外はあり得ないと思いますので。
但し、この関数ですが以下の様な使い方をすると非常に時間が掛かる様です。 (私のPC上では10秒以上の時間が掛かりました。)
文字列から数値型への変換の実行例1
Private Sub StrToInt_Click(sender As Object, e As EventArgs) Handles StrToInt.Click '変換が問題無い例 Dim strValue As String = "123456789" Dim intValue As Integer = 0 intValue = StringToInt(strValue) MsgBox("Integer変換:" & intValue.ToString) '時間計測を「Stopwatch」クラスで行う Dim stopwatch As New Stopwatch() stopwatch.Start() strValue = "ABCD" For i As Integer = 1 To 1000 '関数内でExceptionが発生するはず intValue = StringToInt(strValue) Next stopwatch.Stop() Dim str As String = "" str &= String.Format("ミリ秒単位の経過時間の合計 = {0}", stopwatch.ElapsedMilliseconds) MsgBox(str) End SubVB.NETの Exception 処理は非常に時間が掛かる処理の様で、今回の様な関数の呼び出しを多く行う場合には注意が必要です。 対策としては Exception 処理をなるべくさせないか、その他の方法を取る必要があります。
今回の対策としては Parse メソッドを TryParse メソッドに変更しています。
文字列からInteger型への変換・TryParse
'''
''' 文字列からInteger型にデータ変換その2 ''' ''' <param name="strVal">元の文字列</param> '''変換後データ Function StringToInt2(ByVal strVal As String) As Integer Try Dim intVal As Integer 'TryParseでInteger型に変換 Dim result As Boolean = Int32.TryParse(strVal, intVal) 'ParseでInteger型に変換 Return intVal Catch ex As Exception '例外発生の場合、「0」で返す Return 0 End Try End FunctionTryParse メソッドは変換結果を第2引数に返し、戻り値は True を返します。 尚、失敗した場合は第2引数に0を返し、戻り値は False を返します。
先ほどの使用例をこの関数を使う様に変更すれば、処理時間は格段に向上します。
とにかくネストが深い処理等で処理時間が異常に長い場合には、Exception 処理が絡んでいないかを疑ってみては如何でしょうか。
文字列から数値型への変換の実行例2
Private Sub StrToInt_Click(sender As Object, e As EventArgs) Handles StrToInt.Click '時間計測を「Stopwatch」クラスで行う Dim stopwatch As New Stopwatch() stopwatch.Start() strValue = "ABCD" For i As Integer = 1 To 1000 '呼び出し関数を変更 intValue = StringToInt2(strValue) Next stopwatch.Stop() Dim str As String = "" str &= String.Format("ミリ秒単位の経過時間の合計 = {0}", stopwatch.ElapsedMilliseconds) MsgBox(str) End Sub関連する記事
⇒オブジェクト型から数値型への変換(TryParse)
⇒文字列定数(改行、タブ、バックスペース等)について
⇒文字列変換関数(StrConv)で変換が途中で切れる
⇒文字列変換関数(StrConv)の使い方
-
処理時間の短縮を図る場合に、処理にどのくらいの時間が掛かっているのかを計測する場合があります。
基本的には秒単位での時間計測で問題無い場合は、計測対象の処理の前で時刻を Now() で取得し、 処理終了後に再度 Now() で取得した時刻の差を求めることで計測ができます。処理時間の計測その1
Private Sub TimeMeasure1_Click(sender As Object, e As EventArgs) Handles TimeMeasure1.Click '開始時刻退避 Dim start As DateTime = Now '各種の処理の代わりとしての待ち時間(10秒) System.Threading.Thread.Sleep(10000) '処理時間を計算(現在時刻-開始時刻) Dim timespan As TimeSpan = Now - start MsgBox(String.Format("処理時間 = {0}秒", timespan.TotalSeconds)) End Sub更に、高精度な時間を計測したい場合には、 Stopwatch クラスを用います。
以下のソースでは、 Stopwatch クラス生成後、計測対象処理の直前で Start メソッドで計測開始し、 計測対象処理の直後で Stop メソッドで計測終了します。
処理時間の計測その2
Private Sub TimeMeasure2_Click(sender As Object, e As EventArgs) Handles TimeMeasure2.Click '時間計測を「Stopwatch」クラスで行う Dim stopwatch As New Stopwatch() '計測を開始 stopwatch.Start() '各種の処理の代わりとしての待ち時間(10秒) System.Threading.Thread.Sleep(10000) '計測を終了 stopwatch.Stop() Dim str As String = "" str &= String.Format("経過時間の合計 = {0}", stopwatch.Elapsed) & vbCrLf str &= String.Format("ミリ秒単位の経過時間の合計 = {0}", stopwatch.ElapsedMilliseconds) MsgBox(str) End Sub関連する記事
⇒スレッドタイマの使い方 :[System.Threading.Timer,Delegate,Invoke]
⇒スレッドタイマの使い方(イベント処理が時間が掛かる場合):[System.Threading.Timer,Delegate,Invoke]
⇒引数があるスレッドの実行について(パラメータ付きスレッド)
⇒スレッドを停止させる方法について
-
「コンボボックスの基本的な使い方」の中で コンボボックスの項目のコレクションとしての Itemsプロパティに文字列を設定していますが、 この文字列の代わりにクラスのデータを設定する方法を示します。
クラス名を ComboItemとし表示文字列とコードを内部に持ったクラスを宣言します。
以下にソースを示します。ここで重要なのは、ToString()メソッドを宣言することで、 コンボボックスの選択時に文字列として表示されるのが、このメソッドの戻り値が使用されるためです。'''
''' コンボボックスのItemsに設定される、表示文字列とコードを持ったクラス ''' Public Class ComboItem 'コードデータ退避 Private mintCode As Integer '表示文字列データ退避 Private mstrText As String '''''' 文字列プロパティ ''' Public ReadOnly Property Text As String Get Return Me.mstrText End Get End Property '''''' コードプロパティ ''' Public ReadOnly Property Code As Integer Get Return Me.mintCode End Get End Property '''''' クラスデータの表示文字列を返す ''' '''表示文字列 '''ComboBoxの表示部分には、ToString()メソッドの内容が表示される Public Overrides Function ToString() As String Return mstrText End Function '''''' コンストラクタ ''' '''コード '''表示文字列 Public Sub New(ByVal intCode As Integer, ByVal strText As String) mintCode = intCode mstrText = strText End Sub End Classさてこのクラスを使用したコンボボックスへの設定ですが、以下のソースを見て下さい。
その後、フォームロードイベントでコンボボックスの Itemsプロパティ(ObjectCollection) に、4個クラスデータを生成し追加で初期化を行います。
ボタン1クリックイベントでは、 選択されているIndexの取得を行い、値が -1 で無ければ、 コンボボックスの選択値を取得し、クラスデータとしてキャストしたものから、コード及び文字列を取得し表示します。
ボタン2クリックイベントでは、コンボボックスの選択を解除します。
コンボボックスのItemsプロパティにクラスデータを設定する方法
Public Class frmComboBoxItemsClass ' ===== ' 実際はここに上のクラス宣言がある ' ===== '''''' フォームロードイベント ''' Private Sub frmComboBox_Load(sender As Object, e As EventArgs) Handles Me.Load 'コンボボックス初期化 With Me.ComboBox1 .DropDownStyle = ComboBoxStyle.DropDownList 'クラスを使用してコンボボックスへの設定 Dim cboItem As ComboItem cboItem = New ComboItem(10, "あいうえお") .Items.Add(cboItem) cboItem = New ComboItem(20, "かきくけこ") .Items.Add(cboItem) cboItem = New ComboItem(30, "さしすせそ") .Items.Add(cboItem) cboItem = New ComboItem(40, "たちつてと") .Items.Add(cboItem) End With End Sub '''''' ボタンクリックイベント・選択状態の表示 ''' Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click '選択されているIndexの取得 Dim intIdx As Integer = Me.ComboBox1.SelectedIndex If intIdx <> -1 Then '選択されている項目の取得(クラスデータへのキャスト) Dim cboItem As ComboItem = CType(Me.ComboBox1.SelectedItem, ComboItem) '結果表示 Dim strDsp As String = "コード : " & cboItem.Code & vbCrLf & "文字列 : " & cboItem.Text MsgBox(strDsp, MsgBoxStyle.OkOnly, Me.Text) Else MsgBox("未選択!!", MsgBoxStyle.OkOnly, Me.Text) End If End Sub '''''' ボタンクリックイベント・選択状態の解除 ''' Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click '選択されている状態を解除 Me.ComboBox1.SelectedIndex = -1 End Sub End Class
結果これを実行しますと、以下の様になります。
ボタン1のクリック時は以下の様になります。ボタン2のクリック時はコンボボックスの選択が解除され何も表示されないはずです。
尚、フォームロードイベントでのコンボボックスへの初期化ですが、 クラスデータの配列を宣言し、AddRangeを使って以下の様に書き換えることもできます。'''
''' フォームロードイベント ''' Private Sub frmComboBox_Load(sender As Object, e As EventArgs) Handles Me.Load 'コンボボックス初期化 With Me.ComboBox1 .DropDownStyle = ComboBoxStyle.DropDownList Dim cboItems() As ComboItem = { New ComboItem(10, "あいうえお"), New ComboItem(20, "かきくけこ"), New ComboItem(30, "さしすせそ"), New ComboItem(40, "たちつてと") } .Items.AddRange(cboItems) End With End Sub関連する記事
⇒コンボボックスの基本的な使い方(項目に文字列のみを設定)
⇒ComboBoxの簡単な拡張クラス(枠線色の描画):[WndProc,CreateGraphics,DrawRectangle]
おすすめ本