2

昨夜まで、私は .NET のさまざまなライブラリを使用して XML を解析してきましXmlDocumentXDocument。なぜこれをもっと早く調べなかったのかはわかりませんが、クラスのシリアル化/逆シリアル化を無料で提供する何かが .NET で利用可能であるに違いないと思いました。もちろん、それはXmlSerializerクラスの形式で提供されます。 .

案の定、数行のコードを使用することで、シリアライズとデシリアライズを簡単に行うことができました (ただし、現在書いているコードでは、デシリアライズするだけで済みます)。他のライブラリと必要な単体テストでこれを行う独自のクラスを作成します。しかし問題は、自分のプロパティを読み取り専用にしたいということです。セッターをプライベートにすると、XmlSerializer の作成時に次のエラーが発生します。

一時クラスを生成できません (結果 = 1)。エラー CS0200: プロパティまたはインデクサー 'MyProperty' を割り当てることができません -- 読み取り専用です

これは解決されない問題のように見えるため、回避策が必要です。

案の定、私はこの情報を見つけました。これは、自動プロパティを放棄してプライベート フィールドに戻るだけで、コードをコンパイルできることを示しています。残念ながら、これはコンパイルされますが、コードを実行すると、実際にはデータが逆シリアル化されません。アプリケーションを停止した後、メッセージ ウィンドウに次のようなエントリがいくつかあることに気付きました。

要素 'MyProperty' のスキーマ情報が見つかりませんでした。

これは、XmlSerializer がプライベート フィールドの処理方法を認識していないため、MyProperty に値を割り当てるコードがないためです!!!

StackOverflow で別の解決策DataContractSerializerを提示する回答を見つけました。これは、これまで聞いたことのないa を使用することです。クラスに必要なコード変更を加えましたが、上記と同じメッセージが表示されました。念のためにコードを実行しましたが、XML が逆シリアル化されるときにクラス メンバーが設定されません。

私の特定のケースでは、それを吸ってメンバーが上書きされる(悪い)ことを許可するか、シリアライゼーション/デシリアライゼーションコードをすべて記述するという元のやり方に戻ると考えています自分。ここで私が間違っていることはありますか、それとも XmlSerializer のようなクラスが逆シリアル化中にクラスのプライベートメンバーを設定できるようにすることは不可能ですが、クラスの消費者はそのメンバーを上書きできませんか?

更新:プライベート プロパティの逆シリアル化を行う別の方法を示すさらに別の記事ですが、試してみたところ、動作しません。

以下は、逆シリアル化を試みたクラスの例です。

[Export]
[DataContract]
public class Configuration
{
    [DataMember(Name="Port")]
    private int _port;
    public int Port { get { return _port; }}
}

結果: XmlSerializer で逆シリアル化するとエラーは発生しませんが、XML ファイルの Port 値が 1 の場合、_port と Port の値は 0 になります<Port>1</Port>

もう一つの例:

[Export]
public class Configuration
{
    public int Port { get; set; }
}

結果: 正常にデシリアライズされますが、パブリック セッターは必要ありません。

次のようにクラスを逆シリアル化します。

XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
FileStream reader = new FileStream( "config.xml", FileMode.Open);
Configuration Config = (Configuration)serializer.Deserialize( reader);
reader.Close();
4

3 に答える 3

3

良い答えはありませんが、悪い答えがいくつかあります。順不同:

  1. r/w プロパティを持つ純粋なデータ転送オブジェクトを作成し、それをシリアル化/逆シリアル化に使用できます。次に、DTO を使用して構築することにより、不変ビジネス オブジェクトを初期化できます。

  2. あなたが言及した 2 つのシリアライザー クラスでは、属性とコードの組み合わせによって動作をオーバーライドすることもできます。これで問題を解決するのに十分な可能性がありますが、それだけの価値があるよりも多くの作業が必要になる場合があります。

于 2010-08-07T15:40:07.410 に答える
1

これは、使用するXMLシリアル化方法の問題ではなく、シリアル化自体に関する問題です(バイナリシリアル化で試してみると、同じエラーが発生します)。

プロパティを変更してデフォルトのシリアル化方法を実行できるようにできない場合は、次のようにします。

  1. ISerializableインターフェースを実装します。
  2. GetObjectData実装で、記録する必要のある各フィールドに渡されるSerializationInfoパラメーターに値を追加します。
  3. SerializationInfoパラメーターとStreamingContextパラメーターを受け取るコンストラクター(パブリックである必要はありません)を追加します。このコンストラクターでは、シリアル化中に書き込まれたSerializationInfoからデータを読み戻すことができるため、逆シリアル化されたオブジェクトを生成できます。

さて、これは手動のシリアル化に戻るのと少し似ているように見えるかもしれませんが、それはquesitonのクラスでのみ実行する必要があり、他のメカニズムによってクラスをシリアル化することもできます。

于 2010-08-07T16:11:53.593 に答える
0

最終的に、この質問に対する正しい答えは、プライベート データを逆シリアル化する必要がある場合 (シリアル化は問題ではありません)、XmlSerializer と DataContractSerializer の使用を避けたいということだと思います。私はまだ私が間違っていることを願っていますが、最終的にはジョンが正しいかもしれません.ISerializableを使用するか、今までと同じようにする必要があります.

今夜、あるクラスをパブリック プロパティと共に使用して逆シリアル化を許可し、それを別のクラスでラップすることにしたときに、別のレンガの壁にぶつかりました。逆シリアル化可能なクラスを公開したくありませんでした。読み取り専用プロパティのみを公開するクラス内のプライベート クラスにしたかったのです。問題は、XmlSerializable がプライベートなクラスを処理できないことです。

とりあえずクラスを公開することもできますが、これは最初に機能させるためだけに行うかもしれませんが、そのクラスを公開する必要があるのは意味がないため、別のルートに進みます。

于 2010-08-08T03:43:10.583 に答える