我的数据最好被描述为“洋葱状”,因为每个外层都建立在它下面的数据之上。下面你会看到一个非常简化的版本(我的版本更深层,但在每个级别表现出相同的行为)。
[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
代替并遇到同样的问题。
答案 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
属性修饰的class
或ServiceContractAttribute
,其中该服务包含一个返回上述抽象类型之一的方法?如果是这样,那么您还需要修饰所谓的interface
或class
方法,该方法返回带有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。