トップ回答者
共有メモリにオブジェクトのリストをシリアライズ、デシリアライズしたい

質問
-
いつもお世話になっております。arubi-momoと申します。
開発環境は次の通りです。
Windows7 64bit VisualStudio2017 C#
以前も質問させていただいた共有メモリの件で、Deserializeができずに困っています。
やりたいことは、List<T>形式のリストをそのまま共有メモリに保存し、別のアプリケーションから読み出したいです。
// テストクラス [Serializable()] public class testInfo { public string name { get; set; } public string type { get; set; } public int iValue { get; set; } public float fValue { get; set; } // コンストラクタ public ValInfo() { } } //============= //共有メモリ登録処理 //============= // 共有メモリに登録したいオブジェクト配列を宣言 List<testInfo> infos = new List<testInfo>(); // 共有メモリ生成 private MemoryMappedFile m_mmf = MemoryMappedFile.CreateNew("Global\\TEST", 1024, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, security, HandleInheritability.None); // フォーマッターの宣言 var formatter = new BinaryFormatter(); // 共有メモリに書き込み using (MemoryMappedViewStream stream = m_mmf.CreateViewStream()) { // 共有メモリへ登録 formatter.Serialize(stream, infos ); stream.Flush(); } //============= //共有メモリ読み込み処理 //============= // 共有メモリから読み出した情報を取得するための配列 List<testInfo> infos = new List<testInfo>(); // フォーマッターの宣言 var formatter = new BinaryFormatter(); // 共有メモリを開く using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("Global\\TEST")) { // 共有メモリの内容を取得 using (MemoryMappedViewStream stream = mmf.CreateViewStream()) { object obj = formatter.Deserialize(stream); // ←ここでエラー var objs = obj as List<testInfo>; // objsから情報を取得する処理 ・・・・ } }
共有メモリのSerializeまではうまくいくのですが、Deserializeのところでアセンブリが存在しない旨のエラーが発生します。
デシリアライズができない原因がわからず困っております。
原因にお心当たりのある方がいらっしゃいましたら、何卒、ご教示いただけますようお願いいたします。
回答
-
BinaryFormatterはアセンブリが一致しないと逆シリアライズできません。
異なるアプリケーションでそれぞれでtestInfoクラスを定義していたら型情報も異なることになります。BinaryFormatterを使用したいのであれば、クラスtestInfoをDLLにてして、書き込みするアプリケーションと読み出すアプリケーションの両方からDLLを参照しましょう。
どうしてもDLLにできないというのであれば、以下のようなSerializationBinderを作って偽装すればできないことはないですが、ネストしてるクラスがめんどくさいですよ。
public class Binder<T> : System.Runtime.Serialization.SerializationBinder { public override Type BindToType(string assemblyName, string typeName) { if (typeName.Contains("System.Collections.Generic.List")) { return typeof(List<T>); } else { return typeof(T); } } } //var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); //formatter.Binder = new Binder<testInfo>();//読み出し側のtypeInfoクラスで偽装
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク arubi_momo 2019年1月24日 1:07
すべての返信
-
BinaryFormatterはアセンブリが一致しないと逆シリアライズできません。
異なるアプリケーションでそれぞれでtestInfoクラスを定義していたら型情報も異なることになります。BinaryFormatterを使用したいのであれば、クラスtestInfoをDLLにてして、書き込みするアプリケーションと読み出すアプリケーションの両方からDLLを参照しましょう。
どうしてもDLLにできないというのであれば、以下のようなSerializationBinderを作って偽装すればできないことはないですが、ネストしてるクラスがめんどくさいですよ。
public class Binder<T> : System.Runtime.Serialization.SerializationBinder { public override Type BindToType(string assemblyName, string typeName) { if (typeName.Contains("System.Collections.Generic.List")) { return typeof(List<T>); } else { return typeof(T); } } } //var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); //formatter.Binder = new Binder<testInfo>();//読み出し側のtypeInfoクラスで偽装
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク arubi_momo 2019年1月24日 1:07
-
gekkaさま
いつも大変お世話になっております。
アセンブリが存在しないというのはそういう意味だったんですね!恥ずかしながら今ようやく認識しました。
DLLを作成できればそれが一番早そうだなと思いますので、その方向で進めたいと思います。
また何か行き詰った時にはご相談させていただくかもしれません。
本当にありがとうございました。
今後ともなにとぞ、よろしくお願いいたします。
- 編集済み arubi_momo 2019年1月24日 1:08