C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: C#でシリアライズするとファイルサイズが増える


(過去ログ 107 を表示中)

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■63975 / inTopicNo.1)  C#でシリアライズするとファイルサイズが増える
  
□投稿者/ nobb (1回)-(2012/11/01(Thu) 10:24:14)

分類:[C#] 

開発環境:VisuallStudio2010
言語:C#
.NET:.NET Framework 4 Client Profile

双方向データバインドでデータを入力してもらい、それをファイルに保存するために
以下の機能を実装してみた所、ファイルサイズが増えてしまい困っています。

1.サブフォーム起動時に指定されたファイルがある場合はデシリアライズし、bindingSource.DataSourceに設定
2.ファイルが無い場合はクラスを初期化し設定
3.サブフォームでデータを入力してもらう
4.サブフォームをOKで閉じた場合ファイルに保存する

おおざっぱに以上の形で実装していますが、入力データを変更せず(サブフォーム起動 -> OKで閉じるのみ)でもファイルサイズが増えてしまいます。
何が問題なのかが分からないので、問題が再現する小さなプロジェクトをSkyDriveに上げましたので、どこが悪いのか教えて下さい。

http://sdrv.ms/Rs4sEs

一応、ファイルを保存しますので、保存先として「D:\test」フォルダをfrmSub.csで指定していますので修正の上試してみてください。
使い方としては、起動しbutton1をクリックするとfrmSubが表示されるのでそこに入力して下さい。

以上、よろしくお願いします。
引用返信 編集キー/
■63977 / inTopicNo.2)  Re[1]: C#でシリアライズするとファイルサイズが増える
□投稿者/ howling (29回)-(2012/11/01(Thu) 11:10:30)
nobbさん

なんとなく変なことをしていることはわかりました。
うほ!本当に増えてる!
と思ってファイルサイズ見てみると、増えてるのは300バイト程度。
300文字で考えると大したことないなーと思ってバイナリファイルを比較。

…どこがどう増えてるのかはご覧になりましたか?
見ているデータの上では、自分で内部的に増やしているとしか思えないのですが…。

巨大なプロジェクトでバグが出た場合に、小さいサンプルプロジェクトを作成して、
問題を切り分けするのは良いと思います。
でも、これだけ切り分けできているのなら、手段はもっとありますよ。ね?

多分見ればわかるので、是非是非やってみてください。
「なんでこんなんいるん!?」ってなるの間違いなしなんで(笑

解決お待ちしておりまする〜
引用返信 編集キー/
■63979 / inTopicNo.3)  Re[2]: C#でシリアライズするとファイルサイズが増える
□投稿者/ Hongliang (12回)-(2012/11/01(Thu) 11:22:21)
イベントは、ソース上は

public event PropertyChangedEventHandler PropertyChanged;

という風に記述できますが、コンパイル時には大体次のようなコードに展開されます。

private PropertyChangedEventHandler _PropertyChanged;

[MethodImpl(MethodImplOptions.Synchronized)]
public event PropertyChangedEventHandler PropertyChanged
{
    add { this._PropertyChanged += value; }
    remove { this._PropertyChanged -= value; }
}

ここで注意してほしいのは、_PropertyChangedは普通のインスタンスフィールドであることです。
BinaryFormatterはフィールド全てをシリアライズします。
イベント構文で暗黙に生成されるデリゲートインスタンスも当然その対象です。

さて、オブジェクトをBindingSource.DataSourceに関連づけたとき、
変更通知のためにPropertyChangedイベントにBindingSourceのメソッドが
イベントハンドラとして追加されます。

ここまでを整理しましょう。
初めにサブ画面が開くとき、ファイルが存在しないので新たにpersonインスタンスを生成します。
DataSourceに設定して、PropertyChangedイベントにイベントハンドラが追加されます。
サブ画面終了時、シリアライズします。
最初に述べたように、PropertyChangedイベントに追加されたイベントハンドラもシリアライズされます。

次にサブ画面を開くとき、ファイルが存在するので、デシリアライズします。
もちろん最初に追加されたイベントハンドラごとです。
DataSourceに設定して、PropertyChangedイベントにイベントハンドラが追加されます。
「追加」なので、当然ながらPropertyChangedイベントに登録されたイベントハンドラは
ここで2つになります。
サブ画面終了時のシリアライズでは、この2つのイベントハンドラを両方ともシリアライズします。

以下、やればやるほどシリアライズするイベントハンドラは増えていくことになります。


こういう用途ではイベントハンドラをシリアライズする意味は無いと思われます。
ですので、[NonSerialized]属性を付けてシリアライズの対象外とするのがいいでしょう。
ただしNonSerialized属性はフィールドにしか付けられないので、最初に書いたevent構文には付けられません。
二番目に書いた、add/removeを明示的に記述する構文を使用し、
そのバッキングフィールドとなる_PropertyChangedの方に付けるようにします。

引用返信 編集キー/
■63982 / inTopicNo.4)  Re[2]: C#でシリアライズするとファイルサイズが増える
□投稿者/ nobb (2回)-(2012/11/01(Thu) 11:53:50)
howling さん
早速のご回答有難うございます。

> …どこがどう増えてるのかはご覧になりましたか?
> 見ているデータの上では、自分で内部的に増やしているとしか思えないのですが…。
一応自分でもテキストエディタではありますが、開いて中は確認しました。
targetやらmethodやらは連番で増えていくし、BindingList`1あたりが増えていくのも確認済みではありました。
でもそこから何も浮かばず途方にくれた次第です。

>
> 巨大なプロジェクトでバグが出た場合に、小さいサンプルプロジェクトを作成して、
> 問題を切り分けするのは良いと思います。
> でも、これだけ切り分けできているのなら、手段はもっとありますよ。ね?
もっとあるのでしょうか・・・・。私の知識不足のせいなんだろうとは思いますが、他の手段が思いつきません。
※若干愚痴というか弱音ですけど、社内に私以外プログラムが出来る人間がいない為自身の知識に自信が持てないのが現状です。
※なので、ご助力頂けるとすごくうれしいです。


Hongliangさんからご回答頂いたので、どのようにすればいいか分かってしまいましたが、
雰囲気的におしいorもう何歩かまではせまれていたのかな?と思っています。

ご回答有難うございました。
引用返信 編集キー/
■63984 / inTopicNo.5)  Re[3]: C#でシリアライズするとファイルサイズが増える
□投稿者/ howling (32回)-(2012/11/01(Thu) 12:20:55)
> 他の手段が思いつきません。
うーん…もし私なら、そもそも通常のSerializeは使っていないのかなと。
XMLSerializerで読み書きしてしまうなぁと思います。
もしそれでも増えているのであれば、XML形式なら読めると思いますし、
継承しているために要らないデータが入るのであれば、必要なデータだけ別クラス(または構造体)にもできたかなと。

また、この別クラスだけで自作のシリアライザクラスにかけてあげて、それでも増えるかどうかの検証とか。
(確か既にシリアライザクラスでやってましたもんね)

もしXMLがうまくいって、かつ面倒なのであれば、
XML出力したデータを暗号化する方が楽なのかなーと。
普段XMLで保存/読み取りしていることが多いので、頼りにしてるだけかもしれませんが。

私もC#始めてからまだ1年経ちません。初心者といえる立ち位置だと思います。
が、調べる能力をつければどうにかなるのかなーと!
最悪ここで聞いてますが、聞く立場としてある程度は心得てるつもりです。
周りに聞ける人がいないのはツラいと思いますが、頑張っていきましょう!では。
引用返信 編集キー/
■63986 / inTopicNo.6)  Re[3]: C#でシリアライズするとファイルサイズが増える
□投稿者/ nobb (3回)-(2012/11/01(Thu) 13:23:35)
Hongliang さん
ご回答有難うございます。

> public event PropertyChangedEventHandler PropertyChanged;> private PropertyChangedEventHandler _PropertyChanged;
> 
> public event PropertyChangedEventHandler PropertyChanged
> {
>     add { this._PropertyChanged += value; }
>     remove { this._PropertyChanged -= value; }
> }
に変更し、RaisePropertyChanged内のthis.Propertychangedをthis._PropertyChangedに変更したところ
望みどおりに機能するようになりました。

ただ、MethodImpl属性をつけると以下のエラーが出ます。
「属性 'MethodImpl' は、この宣言型では無効です。'constructor, method' の宣言でのみ有効です」
エラー内容から考えるとコンストラクタ、メソッドでしか使えないようなのですがなぜでしょうか?


解説も書いて頂きありがとうございます。
教えて頂くと、確かにその通りだ!と思えましたが、自分自身では導き出す事ができませんでした。
私の閻魔帳に大事に保存させて頂きたいと思います。

引用返信 編集キー/
■63988 / inTopicNo.7)  Re[4]: C#でシリアライズするとファイルサイズが増える
□投稿者/ Hongliang (13回)-(2012/11/01(Thu) 13:34:26)
> ただ、MethodImpl属性をつけると以下のエラーが出ます。
> 「属性 'MethodImpl' は、この宣言型では無効です。'constructor, method' の宣言でのみ有効です」
> エラー内容から考えるとコンストラクタ、メソッドでしか使えないようなのですがなぜでしょうか?

あ、そうでしたか。
それなら、addとremoveにそれぞれ付けるようにしてください。
addとremoveは、内部的にはただのメソッドです。

// ハンドラの追加・削除にスレッドが絡まないなら必須ではないですが。
引用返信 編集キー/
■63989 / inTopicNo.8)  Re[4]: C#でシリアライズするとファイルサイズが増える
□投稿者/ nobb (4回)-(2012/11/01(Thu) 13:34:38)
No63984 (howling さん) に返信
>>他の手段が思いつきません。
> うーん…もし私なら、そもそも通常のSerializeは使っていないのかなと。
> XMLSerializerで読み書きしてしまうなぁと思います。
XMLSerializerも考えの中ではあったのですが、保存されたファイルを開かれた場合(拡張子を変更していても)中身が読み書き出来てしまうので
ファイルが(構造的に)壊れた!となってしまうのは避けたいなと思い却下しました。


自作クラスとかXMLから暗号化とか方法は色々ありますね。
うーん・・・自分でも思いつくようにならなければ!がんばります!
ありがとうございました!
引用返信 編集キー/
■63990 / inTopicNo.9)  Re[5]: C#でシリアライズするとファイルサイズが増える
□投稿者/ nobb (5回)-(2012/11/01(Thu) 13:37:52)
> それなら、addとremoveにそれぞれ付けるようにしてください。
> addとremoveは、内部的にはただのメソッドです。
>
> // ハンドラの追加・削除にスレッドが絡まないなら必須ではないですが。
今回スレッドは全く絡まないのですが、addとremoveに付けるようにしておきます。

ご親切に教えて頂きありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -