- PR -

列挙型の変数を持ったクラスをシリアライズするとエラー?

1
投稿者投稿内容
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2006-06-05 10:51
こんにちは。お世話になってます。

今、VB.NET 2005でアプリケーション開発を行っています。
XmlSerializerを使って、オブジェクトをXML化する汎用的なクラスを作成しました。

コード:


Imports System.IO
Imports System.Xml.Serialization

Namespace IO
''' <summary>
''' オブジェクトをシリアライズしてXMLファイルに出力したり、XMLファイルをデシリアライズしてオブジェクトを生成したりするクラス
''' </summary>
''' <typeparam name="T">オブジェクトの型</typeparam>
''' <remarks></remarks>
Public Class ObjectSerializer(Of T)
Private mFileName As String
Private mPath As String = Application.StartupPath

''' <summary>
''' XMLファイル名
''' </summary>
''' <param name="fileName"></param>
''' <remarks></remarks>
Public Sub New(ByVal fileName As String)
mFileName = fileName
End Sub

Property Path() As String
Get
Return mPath
End Get
Set(ByVal value As String)
mPath = value
End Set
End Property

''' <summary>
''' オブジェクトをシリアライズしてXMLファイルに出力する
''' </summary>
''' <param name="obj"></param>
''' <remarks></remarks>
Public Sub Serialize(ByVal obj As T)

Dim serializer As XmlSerializer = New XmlSerializer(GetType(T))
Dim stream As FileStream = New FileStream(mPath & mFileName, FileMode.Create)
Try
serializer.Serialize(stream, obj)
Finally
stream.Close()
End Try

End Sub

''' <summary>
''' XMLファイルをデシリアライズしてオブジェクトを生成する
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Function Deserialize() As T
Dim path As String = Application.StartupPath & mFileName
If File.Exists(path) Then
Dim serializer As XmlSerializer = New XmlSerializer(GetType(T))
Dim stream As FileStream = New FileStream(path, FileMode.Open)
Try
Return CType(serializer.Deserialize(stream), T)
Finally
stream.Close()
End Try
Else
Return Nothing
End If
End Function

End Class
End Namespace




そして、以下のようなテストクラスがあります。

コード:


Public Class XmlTest1
Public a As Integer
Public b As New XmlTest2
End Class

Public Class XmlTest2
Public b As Integer
Public c As Types = Types.aa
'Public d As EnumTest.Types = EnumTest.Types.cc '<=こいつを足すとエラー
Enum Types
aa
bb
End Enum
End Class

Public Class EnumTest
Enum Types
cc
dd
End Enum
End Class




そして、以下のように上記で作成したクラスを実行してみると、

コード:


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim xml As New ObjectSerializer(Of XmlTest1)("\aaa.xml")
Dim obj As New XmlTest1

xml.Serialize(obj)
End Sub
End Class




XmlTest2の列挙型変数 d がなければ正常に動作しますが、コメントをはずすと、

型 '○○○.XmlTest1' を反映中にエラーが発生しました。

というエラーが出ます。エラーのスタックをみるとImportTypeMappingでとまっているので、
シリアライズ時にEnumTestの型が取れていないような感じです。

XmlTest1からXmlTest2の型をたどれて取れているようで、XmlTest2内の列挙型も問題なく型を取れていると思います。
なぜか、シリアライズ対象のクラス外の列挙型は型が取れずに失敗しているようです。

上記のシリアライズ汎用クラスは、もっと大きなオブジェクトをシリアライズ・デシリアライズしても、今まで問題なく動いていましたが、今回のように列挙型を含むクラスにしたとたんにエラーが出るようになりました。

原因や、対処方法をご存知の方はおられないでしょうか?よろしくお願いします。



[ メッセージ編集済み 編集者: maru 編集日時 2006-06-05 11:00 ]
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2006-06-05 13:55
引用:

maruさんの書き込み (2006-06-05 10:51) より:

XmlTest1からXmlTest2の型をたどれて取れているようで、XmlTest2内の列挙型も問題なく型を取れていると思います。なぜか、シリアライズ対象のクラス外の列挙型は型が取れずに失敗しているようです。


検証したわけではないのですが、パっと見た感じ、
「Types」という列挙体名で衝突しているからではないでしょうか。

どちらか一方を別の名前にしたら、動作したりしませんか?
(動作するのであれば、原因はそこだということになります)

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2006-06-05 15:27
こんにちは。
返答ありがとうございます。

じゃんぬねっとさんの言われるように、列挙型の名前を変えてみると動きました。

でも、それぞれのクラスに属している列挙型なのに、なぜ名前が衝突しているという
ことになるのでしょうか?

すでに同一列挙名をたくさん使っており、いまさらかえることはできません
何か対処方法はありますか?
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-06-05 16:13
// あまり同じ型名になるようにはしない方が良いと思います。コーディングも面倒だし。

それぞれの列挙型に XmlTypeAttribute 属性で TypeName を明示したら良いかと思います。
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2006-06-05 17:05
返答ありがとうございます。

>あまり同じ型名になるようにはしない方が良いと思います。コーディングも面倒だし。
○○区分クラスというのがあって、その中にそれぞれTypesという列挙体を持たせていました。
クラス名(名前空間)がユニークなので、その区分クラスに関して列挙体はTypesという
ものに統一していました。今まで、問題なかったのですが、シリアライズするクラス
を使い出した時点で今回のような問題にぶち当たりました。

コーディングが面倒とは感じないのですが、列挙体の型名もユニークにしたほうがいいということでしょうか?

>それぞれの列挙型に XmlTypeAttribute 属性で TypeName を明示したら良いかと思います。
申し訳ありません。XmlTypeAttribute の具体的な使い方がよくわからないので、上記の
ソースコードに書いてみていただけないでしょうか?

ググってみて調べたのですがXmlTypeAttribute についてよく理解できませんでした。


Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-06-05 17:13

MSDN のサンプル じゃ駄目ですか?
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2006-06-06 10:53
おはようございます。
Enumの場合は、こちらでやればよさそうですね。

ただ、結局ソースを修正する必要があるので素直にEnumの型名を換えます
VS2005はリファクタリング機能があるので助かります。

でも、やはりなぜ衝突しているとなるのかが理解できませんが・・・。
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2006-06-06 11:33
こんにちは。

あれから、列挙体の型名がダブらないように変更してみました。
今までのエラーは出なくなりましたが、今度は

{"インスタンス検証エラー : '0' は クラス名.列挙型名 の有効な値ではありません。"}

というエラーが出るようになりました。
調べてみると、そのエラーの出るクラス名.列挙型は、AAA = 1 のように、
属性に数値指定しているもので落ちているようです。

今のところ影響ないので、とりあえず数値指定をやめてみることにします。


[ メッセージ編集済み 編集者: maru 編集日時 2006-06-06 11:34 ]
1

スキルアップ/キャリアアップ(JOB@IT)