質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

3回答

5012閲覧

【C#】stringをクラスにParseしたい

syogakusya

総合スコア67

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2016/10/06 03:18

編集2016/10/06 03:19

###質問

通信などの理由でstringと相互に変換できる通信データクラスの仕組みを考えています。
stringにする仕組みはできたのですが、stringをクラスインスタンスにデシリアライズする仕組みが思いつきません。

C#

1Namespace Somewhere 23 public interface ITsushinSupporting 45 string AsString(); 678 9abstract class Data: Somewhere.ITsushinSupporting 1011 public string AsString() 1213 // GetTypeしてプロパティ値を名前順で全部とってきてstring化してカンマ区切りで結合する 14 // どんな派生クラスでもこれでstring化できる 151617 18class DataA: Data 1920 // プロパティが2つのPOCO 2122 23class DataB: Data 2425 // プロパティが3つのPOCO 26

ここでParseメソッドのような静的メソッドがDataクラスにほしいのですが、渡されたstringから元はどのクラスインスタンスだったのかが分からないことに気がつきました。
そこでDataクラスにTypeIdという抽象プロパティを実装し、その値をstring化するときに先頭にくるようにして、その値が一致する型にデシリアライズしようと考えました。

C#

1Namespace Somewhere 23 public interface ITsushinSupporting 45 string AsString(); 678 9abstract class Data: Somewhere.ITsushinSupporting 1011 propected abstract int TypeId{ get;12 13 public string AsString() 1415 // GetTypeしてプロパティ値を名前順で全部とってきてstring化してカンマ区切りで結合する 16 // どんな派生クラスでもこれでstring化できる 17 // プロパティ値を名前順でとってくるとき、TypeIdだけは無条件で先頭に持ってくる 1819 20 public Data Parse(string s) 2122 // Dataクラスの派生クラスのうちTypeIdが一致するものを探してその型のインスタンスを作る 232425 26class DataA: Data 2728 // プロパティが3つのPOCO 29 30 protected override int TypeId => 1; 3132 33class DataB: Data 3435 // プロパティが4つのPOCO 36 37 protected override int TypeId => 2; 38

しかし、この方法だとParseメソッド内をどのように実装すればいいか思いつきませんでした。
派生クラスを全て取得する方法も分かりませんし、TypeIdは実装上インスタンスプロパティですし、その型のTypeが取得できてもそのインスタンスを生成する方法が分かりません。
そもそも基底クラスの静的メソッドで派生クラスのインスタンスを生成したり、派生クラスはPOCOでなければならなかったり、結局通信で送られてきたデータをParseでクラスインスタンスに戻しても、利用する側ではif(...is DataB)といった分岐を行わなければなりませんし、それとTypeIdをpublicにしてswitchするのとどっちがいいのかもよくわかりません。
同じようなことをしたことがある方、いい方法を教えてください。
目的さえ果たせれば全然違う実装でも構いません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

System.Xml.Serialization.XmlSerializerクラスの
Serialize、Deserializeメソッドあたりはどうでしょう?

投稿2016/10/06 03:39

lain

総合スコア161

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

こんにちは。

そこでDataクラスにTypeIdという抽象プロパティを実装し、その値をstring化するときに先頭にくるようにして、その値が一致する型にデシリアライズしようと考えました。

GetType()してクラス名をToString()で取り出し、クラス名を記録すると良いように思います。
回復時はType.GetType(クラス名)でクラスの型を取得できるので、そのInvokeMember(..., BindingFlags.CreateInstance, ...)すれば当該クラスのインスタンスを作れる筈です。

でも、いろいろ面倒なのでシリアライザを使った方が楽で良いと思います。
KIYOSHIさんが紹介されているJson.NETはサードパーティ製で一番メジャーなシリアライザです。

投稿2016/10/06 03:57

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

syogakusya

2016/10/07 01:51

ありがとうございます。 どちらの方法でも目的を実現できることを確認しました。 こういった実装自体の良し悪しについてはどうなのでしょう? オブジェクト指向ということを考えると、この一連のクラスにデータを受信した後の処理(たとえばローカルにファイルを作成して履歴として残すなど)を実装することで多態性を実現するべきなのでしょうか?
syogakusya

2016/10/07 01:57

それと、当たり前のことなのですが、DataB.ParseをしてもDataAのインスタンスが取得できたりしますよね…そもそも考え方がどこかおかしいのでしょうか?
Chironian

2016/10/07 02:19

> どちらの方法でも目的を実現できることを確認しました。 > こういった実装自体の良し悪しについてはどうなのでしょう? シリアライズ・ライブラリを使うか使わないか でしょうか? メジャーなライブラリを使える時はライブラリを使った方がソフトの信頼性は上がると思います。 デシリアライズ後の処理が派生先クラス毎に異なるのであれば、それを仮想関数で記述するとスマートですね。 > 当たり前のことなのですが、DataB.ParseをしてもDataAのインスタンスが取得できたりしますよね…そもそも考え方がどこかおかしいのでしょうか? リフレクションを使えばData.Parse内でもデシリアライズできますので、Data.Parseで処理するのがスマートと思います。派生クラスが増えてもシリアライズ/デシリアライズ処理を書かなくてよいですから、随分楽です。 ただし、リフレクションは遅いのでDataA, DataBのParseで処理することもありえると思います。派生クラスがあまり増えない、かつ、かなり巨大なデータを保存する時はこちらを選択する場合もあると思います。その時にDataAが届いているのにDataB.Parseを呼ぶのは単なるバグと思います。
syogakusya

2016/10/07 03:21 編集

なるほど。 派生クラスAではデータベースにWriteし、派生クラスBではハードディスク上にファイルを作るとした場合、DataクラスにDoみたいな抽象メソッドを実装するイメージでしょうか。 その場合、Doメソッドの引数としてDB接続オブジェクトとファイルストリームを渡さなければならない気がするのですが、そもそも全然ちがいますか 追記: 言葉ばかりになってしまいすみません。 業務の内容なのでソースをそのまま載せることはできないのですが、近いうちにぼかしながら今のコードを再現して載せようと思います。
Chironian

2016/10/07 03:19

DataAがデータベースへWriteするなら、DataA自身がDB接続オブジェクトを保持しておいた方が良いです。DataBもファイルストリームを保持した方が良いです。 Dataクラスがそれぞれを保持して、パメータとして渡すものではないと思います。 派生クラス毎に異なるデータは派生クラスが保持するべきです。基底クラスがそれを保持するのは多態性の設計としてよい設計ではありません。 この辺はシリライズの話ではなく多態性の設計方針の話と思います。もし、まだ長くなるようでしたら、別途質問を立てられた方が良いと思います。
syogakusya

2016/10/07 03:23

そうですね。メインテーマについては解決したので質問を改めて立てようと思います。 ありがとうございました。
guest

0

Classのシリアライズ・デシリアライズでも可能ですが、
通信であれば、JSONはいかがでしょうか?
以下URLなど参考になると思います。
(Json.NETを使ってあります。)
http://qiita.com/ta-yamaoka/items/a7ff1d9651310ade4e76

投稿2016/10/06 03:28

KIYOSHI

総合スコア268

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問