VB2008で、構造体というものを勉強しています。
例えば、以下のような構造体を作成したとします。
Private Structure StrucTest
Dim Data1 As String
Dim Data2 As Integer
Dim Data3 As Boolean
Dim Data4() As String
End Structure
この構造体を、以下のように利用したとします。
Dim Test1 as StrucTest
Dim Test2 as StrucTest
(以下、値をそれぞれの変数にセット)
このとき、構造体変数Test1とTest2の比較を行い、内容が同じであるかどうかをチェックしたいのですが、
簡単に比較できる方法はありますでしょうか?
ポイントは、
・構造体の要素Data1〜Data3については、値が一致していることが条件。
・構造体の要素Data4については、配列の数が一致し、かつ各配列の値が一致していることが条件。
どうぞご教授のほどよろしくお願いいたします。
IEquatable(Of StrucTest) を実装し、その Equals メソッドで
> ・構造体の要素Data1〜Data3については、値が一致していることが条件。
> ・構造体の要素Data4については、配列の数が一致し、かつ各配列の値が一致していることが条件。
を判定します。
配列要素の比較には、SequenceEqual 拡張メソッドが楽ですかね。
// こんなにメンバが多いものなら構造体に向いてるとは思えませんね。「値」という雰囲気でもないし。
# コードを書いているうちに、Hongliang さんの回答がついていたけれども、
# 折角書いたのでそのまま投稿しておきます。
----
配列を含む構成の場合、クラスにすることも検討してみてください。
http://msdn.microsoft.com/ja-jp/library/ms229017.aspx
> 内容が同じであるかどうかをチェックしたいのですが
> 簡単に比較できる方法はありますでしょうか?
「簡単に比較」というのは、その構造体を利用する側の話でしょうか。
それとも、構造体を実装する段階での話でしょうか。
利用する側にとって簡単なのは、= 演算子を実装することでしょうか。
「If Test1 = Test2 Then」で比較できるようになりますから。
Shared Operator =(ByVal a As StrucTest, ByVal b As StrucTest) As Boolean
If (a.Data1 = b.Data1) AndAlso (a.Data2 = b.Data2) AndAlso (a.Data3 = b.Data3) Then
If (a.Data4 IsNot Nothing) AndAlso (b.Data4 IsNot Nothing) Then
Return a.Data4.SequenceEqual(b.Data4)
Else
Return (a.Data4 Is Nothing) AndAlso (b.Data4 Is Nothing)
End If
Else
Return False
End If
End Operator
手を抜かずに実装するのであれば、さらに IEquatable(Of T) も実装しましょう。
http://msdn.microsoft.com/ja-jp/library/ms229031.aspx
http://msdn.microsoft.com/ja-jp/library/ms131187.aspx
http://msdn.microsoft.com/ja-jp/library/ms131190.aspx
http://dobon.net/vb/dotnet/beginner/equals.html
あるいは、下記のようにシリアライザを通じて比較することもできます。
パフォーマンスの点では劣りますが、そのかわり、新たなメンバが増えても
コードを変更せずに済むというメリットがあります。
(この場合、各メンバが永続化可能である必要がありますけれど)
<Serializable()> _
Private Structure StrucTest
Dim Data1 As String
Dim Data2 As Integer
Dim Data3 As Boolean
Dim Data4() As String
Shared Operator =(ByVal a As StrucTest, ByVal b As StrucTest) As Boolean
Return BitConverter.ToString(a.ToBinary()) = BitConverter.ToString(b.ToBinary())
End Operator
Shared Operator <>(ByVal a As StrucTest, ByVal b As StrucTest) As Boolean
Return BitConverter.ToString(a.ToBinary()) <> BitConverter.ToString(b.ToBinary())
End Operator
Private Function ToBinary() As Byte()
Dim bf As New BinaryFormatter()
Using stm As New MemoryStream()
bf.Serialize(stm, Me)
stm.Position = 0
Return New BinaryReader(stm).ReadBytes(stm.Length)
End Using
End Function
End Structure
Hongliangさま、魔界の仮面弁士さま、ご回答ありがとうございました。
方針としましては、魔界の仮面弁士さまご提案のシリアライザというものを利用したいと思います。
しかしながら、勉強不足のためか、よく分からない点があります。アドバイスを頂けますでしょうか?
・この構造体の利用は、例えば、初期状態の画面項目(TextBoxやCheckBox・ListBoxなど)の各値と、
ある時点の画面項目の各値を比較して、どれか一つでも変更されているかどうかを確認するこのにも
使用できればいいと考えています。
このため、
初期状態→画面初期値を構造体変数1にセットする。
セットした値自体は変更等を行わない。
ある時点→画面の各値を構造体変数2にセットする。
この構造体の値は別用途で使用するが、画面初期値(変数1)との比較を行いたい。
という利用方法を考えています。
この場合は、やはりクラスにしたほうが良いのでしょうか?
・紹介頂いたサイトで、構造体にするかクラスにするかの記事の中に、「ボックス化」という言葉がありました。
これが今回実現しようとすることとどのような関係があるかを確認したくてその説明を読んでみたのですが、
勉強不足でよく理解できませんでした。
ボックス化とは、簡単に言えばどのようなことなのでしょうか?
・魔界の仮面弁士さまが示してくださいました、シリアライザを使用した例の中で、構造体の宣言の前に
<Serializable()> _ というものが書いてありました。
これはどういったもので、どのような時に書くものなのでしょうか?
よろしくお願いいたします。