使用DataContractSerializer序列化子类实例的实用方法是什么?
例如,以下是数据类型:
[DataContract]
public class Car
{
public Car()
{
Wheels = new Collection<Wheel>();
}
[DataMember]
public Collection<Wheel> Wheels { get; set; }
}
[DataContract]
public abstract class Wheel
{
[DataMember]
public string Name { get; set; }
}
[DataContract]
public class MichelinWheel : Wheel
{
[DataMember]
public string Wheel1Test { get; set; }
}
[DataContract]
public class BridgeStoneWheel : Wheel
{
[DataMember]
public string Wheel2Test { get; set; }
}
下面是创建一辆有两个不同车轮的汽车的代码:
Car car = new Car();
MichelinWheel w1 = new MichelinWheel { Name = "o1", Wheel1Test = "o1 test" };
BridgeStoneWheel w2 = new BridgeStoneWheel { Name = "o2", Wheel2Test = "o2 test" };
car.Wheels.Add(w1);
car.Wheels.Add(w2);
现在,如果我尝试使用DataContractSerializer来序列化汽车,我会得到一个异常,说MichelWhereel不是预期的。我必须像这样修改Wheel类才能使其工作:
[DataContract]
[KnownType(typeof(MichelinWheel))]
[KnownType(typeof(BridgeStoneWheel))]
public abstract class Wheel
{
[DataMember]
public string Name { get; set; }
}
但这种方法并不实用,因为我无法在创建各种轮子之前列出它们。每次创建新品牌的轮子后更改轮子类也是不现实的,因为它们可能是在第三方代码中创建的。
那么,当使用DataContractSerializer时,序列化子类实例的实用方法是什么呢?
感谢
使用WCF 4中的DataContractResolver
查看本文。您还可以将KnownTypeAttribute
与将使用反射获取所有类型的方法的传递名称一起使用。无论如何,服务要求在启动之前知道所有类型。
有几种方法可以使已知类型可用于服务。
上面概述了最简单的方法,但很明显,这需要在添加新类型时重新编译,而且根据您的配置,避免循环依赖关系可能会很困难。
您还可以配置KnownTypes:
- 通过服务配置文件(只需要重新启动服务)
- 将它们添加为通过服务接口上的静态方法提供的服务已知类型,正如Ladislav Mrnka所指出的,您可以通过反射获得该类型(您可能可以反射所有加载的程序集,并将其上具有DataContact属性的所有类型返回为已知类型,但我找不到这样的示例。)
- 实现您自己的获取方式(可能通过配置文件中的一些定制配置元素,也可能只是通过文本文件)