数据契约无法序列化集合成员
本文关键字:集合 成员 序列化 契约 数据 | 更新日期: 2023-09-27 18:18:09
我的数据最好被描述为"像洋葱一样",因为每个外层都建立在它下面的一层之上。下面你将看到一个非常简化的版本(我的版本更深层,但在每一层都显示相同的行为)。
[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
的实例,并使用ObservableCollection
附带的.Add
将Test
对象添加到它。
当我序列化和反序列化这个结构时,我得到以下
<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>
输出在TestGroup
中省略了DataMember
s。随着我对洋葱的深入,没有更高的DataMember
被包括在内(即使来自抽象类)。我已经尝试将[KnownType(typeof(TestGroup))]
添加到TestGroup
和AbstractTestGroup
中,但没有成功。
问题:为什么我不能在TestGroup
类中序列化DataMember
Why
?
后续问题:是否有另一种方法来序列化和反序列化这种形状的结构?我计划在本地使用输出来"加载"用户指定的配置。如果可以的话,我希望不必指定自己的序列化方案。
对于那些感兴趣的人,这里是我如何生成类,序列化和反序列化它。
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
代替,并有同样的问题。
属性why没有序列化的原因是TestGroup是一个集合。datcontract特别对待集合。最终结果是只存储集合中的数据,而不存储任何属性。
列表以任何其他列表都可以读入的方式存储。唯一的区别是集合和字典。一个很好的参考是http://msdn.microsoft.com/en-us/library/aa347850%28v=vs.110%29.aspx
更新:我在网上看到了一些可能对你有帮助的东西。特别是,将抽象类属性声明更改为以下内容:
[DataContract]
[KnownTypes(typeof(Test))]
public abstract class AbstractTest { /* ... */ }
你可以看看MSDN上KnownTypesAttribute
的文档。显然,还有一个构造函数重载,它接受一个字符串,该字符串解析为一个方法名,该方法名将通过反射找到,并由DataContractSerializer
调用,以确定基类的已知类型(如果您有多个已知类型和/或可能需要动态返回可能在编译时不知道的已知类型)。还有web.config
XML配置用于设置已知类型。
UPDATE:我注意到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
属性到派生类的重写属性。
UPDATE: OK,可能有一个额外的维度导致你引用的行为。您是否有使用ServiceContractAttribute
属性装饰的interface
或class
,其中服务包含返回上述抽象类型之一的方法?如果是这样,那么您还需要修饰上述返回具有ServiceKnownTypesAttribute
属性的抽象类型的interface
或class
方法。下面是一个简单的示例:
[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 .