4

私は、各外側のレイヤーがその下のレイヤーの上に構築されているという点で、「タマネギのような」と最もよく説明されているデータを持っています。以下に、非常に単純化されたバージョンが表示されます (私のものは数層深くなりますが、各レベルで同じ動作を示します)。

[CollectionDataContract]
public abstract class AbstractTestGroup : ObservableCollection<AbstractTest>
{
    [DataMember]
    public abstract string Name { get; set; }
}

[CollectionDataContract]
[KnownType(typeof(Test))]
public class TestGroup : AbstractTestGroup
{
    public override string Name
    {
        get { return "TestGroupName"; }
        set { }
    }

    [DataMember]
    public string Why { get { return "Why"; } set { } }
}

[DataContract]
public abstract class AbstractTest
{
    [DataMember]
    public abstract string SayHello { get; set; }
}


[DataContract]
public class Test : AbstractTest
{
    //Concrete class - members in this class get serialized
    [DataMember]
    public string Month { get { return "June"; } set { } }

    public override string SayHello { get { return "HELLO"; } set { } }
}

のインスタンスを作成し、付属の を使用してオブジェクトをTestGroup追加します。Test.AddObservableCollection

この構造をシリアライズおよびデシリアライズすると、次のようになります。

<TestGroup xmlns="http://schemas.datacontract.org/2004/07/WpfApplication2" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <AbstractTest i:type="Test">
        <SayHello>HELLO</SayHello>
        <Month>June</Month>
    </AbstractTest>
</TestGroup>

出力ではDataMembers inが省略されていTestGroupます。タマネギを深く掘り下げると、DataMemberより高い s は含まれません (抽象クラスからでも)。[KnownType(typeof(TestGroup))]私は両方に追加しようとしましたが、成功しませんでしたTestGroupAbstractTestGroup

質問:クラスDataMember Whyでをシリアル化できないのはなぜですか?TestGroup

フォローアップの質問:この形状の構造をシリアライズおよびデシリアライズする別の方法はありますか? 出力をローカルで使用して、ユーザーが指定した構成を「ロード」することを計画しています。回避できるのであれば、独自のシリアル化スキームを指定する必要はありません。


興味のある方は、クラスの生成、シリアライズ、デシリアライズの方法について説明します。

TestGroup tg = new TestGroup();
tg.Add(new Test());

DataContractSerializer ser = new DataContractSerializer(typeof(TestGroup));
MemoryStream memoryStream = new MemoryStream();
ser.WriteObject(memoryStream, tg);

memoryStream.Seek(0, SeekOrigin.Begin);
string str;
using (StreamReader sr = new StreamReader(memoryStream))
    str = sr.ReadToEnd();

編集:Serializable代わりに使用するように変更してみましたが、同じ問題がありました。

4

2 に答える 2

2

プロパティ Why​​ がシリアル化されない理由は、TestGroup がコレクションであるためです。また、DataContract はコレクションを特別に扱います。最終的に、コレクション内のデータのみが保存され、プロパティは保存されません。

リストは、他のリストが読み込むことができる方法で保存されます。唯一の違いは、コレクションとディクショナリの間です。良いリファレンスはhttp://msdn.microsoft.com/en-us/library/aa347850%28v=vs.110%29.aspxです

于 2014-06-04T14:52:01.277 に答える
-1

更新:オンラインで役立つ情報をいくつか見てきました。特に、抽象クラスの属性宣言を次のように変更します。

[DataContract]
[KnownTypes(typeof(Test))]
public abstract class AbstractTest { /* ... */ }

で MSDN のドキュメントを参照できますKnownTypesAttribute。どうやら、リフレクションを介して検出され、基本クラスの既知の型を決定するために呼び出されるメソッド名に解決される文字列を受け取るコンストラクターのオーバーロードもありDataContractSerializerます (既知の型が複数ある場合、および/または必要な可能性がある場合)。コンパイル時に認識されていない可能性のある既知の型を動的に返すため)。web.config既知の型を設定するための XML 構成もあります。

更新:KnownTypesAttribute OPのコード例で属​​性が誤用されているように見えることに気付きました。そのため、動作するはずの完全なコードを使用して上記を詳しく説明したいと思いました。

[CollectionDataContract]
[KnownTypes(typeof(TestGroup))] // Need to tell DCS that this class's metadata will be included with members from this abstract base class.
public abstract class AbstractTestGroup : ObservableCollection<AbstractTest>
{
    [DataMember]
    public abstract string Name { get; set; }
}

[CollectionDataContract]
//[KnownTypes(typeof(Test))] -- You don't need this here....
public class TestGroup : AbstractTestGroup
{
    [DataMember] // Even though this is a derived class, you still need to tell DCS to serialize this overridden property when serializing this type
    public override string Name
    {
        get { return "TestGroupName"; }
        set { }
    }

    [DataMember]
    public string Why { get { return "Why"; } set { } }
}

[DataContract]
[KnownTypes(typeof(Test))] // Again, you need to inform DCS
public abstract class AbstractTest
{
    [DataMember]
    public abstract string SayHello { get; set; }
}


[DataContract]
public class Test : AbstractTest
{
    //Concrete class - members in this class get serialized
    [DataMember]
    public string Month { get { return "June"; } set { } }

    [DataMember] // Even though this is a derived class, you still need to tell DCS to serialize this overridden property when serializing this type
    public override string SayHello { get { return "HELLO"; } set { } }
}

KnownTypesAttribute上記の例の属性の横にあるコメントを参照してください。

更新:DataMemberAttribute派生クラスのオーバーライドされたプロパティに属性を追加しました。

更新: OK、参照している動作の原因となっている追加のディメンションがある可能性があります。上記の抽象型のいずれかを返すメソッドがサービスに含まれている場合、属性で装飾されたinterfaceまたは がありますか? その場合は、属性を持つ抽象型を返す前述のorメソッドも装飾する必要があります。簡単で汚い例は次のとおりです。classServiceContractAttributeinterfaceclassServiceKnownTypesAttribute

[ServiceContract]
//[ServiceKnownTypes(typeof(TestGroup))] -- You could also place the attribute here...not sure what the difference is, though.
public interface ITestGroupService
{
    [OperationContract]
    [ServiceKnownTypes(typeof(TestGroup))]
    AbstractTestGroup GetTestGroup();
}

HTH。

于 2013-06-13T16:21:59.323 に答える