DataContract无法序列化集合成员

时间:2013-06-13 15:41:07

标签: c# serialization datacontractserializer datacontract

我的数据最好被描述为“洋葱状”,因为每个外层都建立在它下面的数据之上。下面你会看到一个非常简化的版本(我的版本更深层,但在每个级别表现出相同的行为)。

[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附带的.Add向其添加ObservableCollection个对象。

当我对此结构进行序列化和反序列化时,我得到以下内容

<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>

输出已停止DataMember中的TestGroup。随着我对洋葱的深入了解,不包括更高级别的DataMember(即使是抽象类)。我尝试向[KnownType(typeof(TestGroup))]TestGroup添加AbstractTestGroup但未成功。

问题:为什么我无法序列化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代替并遇到同样的问题。

2 个答案:

答案 0 :(得分:2)

属性Why未序列化的原因是TestGroup是一个集合。 DataContract专门处理集合。最终结果是只存储集合中的数据,并且不存储任何属性。

列表以任何其他列表可以读取的方式存储。唯一的区别在于集合和字典之间。一个很好的参考是http://msdn.microsoft.com/en-us/library/aa347850%28v=vs.110%29.aspx

答案 1 :(得分:-1)

更新:我在网上看到过一些可能对您有所帮助的内容。特别是,将抽象类属性声明更改为以下内容:

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

您可以在KnownTypesAttribute上查看MSDN上的文档。显然,还有一个构造函数重载,它接受一个解析为通过反射找到的方法名称的字符串,并由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属性旁边的评论。

UPDATE:DataMemberAttribute属性添加到派生类的重写属性中。

更新:好的,可能会有一个添加的维度导致您引用的行为。您是否拥有使用interface属性修饰的classServiceContractAttribute,其中该服务包含一个返回上述抽象类型之一的方法?如果是这样,那么您还需要修饰所谓的interfaceclass方法,该方法返回带有ServiceKnownTypesAttribute属性的抽象类型。下面是一个快速而肮脏的例子:

[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。