2016-09-21 63 views
7

我有2个班与继承类无效的输出

[DataContract, KnownType(typeof(B))] 
public class A 
{ 
    [DataMember] 
    public string prop1 { get; set; } 
    [DataMember] 
    public string prop2 { get; set; } 
    [DataMember] 
    public string prop3 { get; set; } 
} 

[DataContract] 
public class B : A 
{ 
    [DataMember] 
    public string prop4 { get; set; } 
} 

和下面的方法:

List<B> BList = new List<B>(); 
BList = new List<B>() { new B() { prop1 = "1", prop2 = "2", prop3 = "3", prop4 = "4" } }; 
List<A> AList = BList.Cast<A>().ToList(); 
DataContractSerializer ser = new DataContractSerializer(typeof(List<A>)); 
FileStream fs = new FileStream(@"C:\temp\AResult.xml", FileMode.Create); 
using (fs) 
{ 
    ser.WriteObject(fs, AList); 
} 

后者写到这了outcoming XML文件:

<ArrayOfProgram.A xmlns="http://schemas.datacontract.org/2004/07/foo" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 
<Program.A i:type="Program.B"> 
<prop1>1</prop1> 
<prop2>2</prop2> 
<prop3>3</prop3> 
<prop4>4</prop4> 
</Program.A></ArrayOfProgram.A> 

如何可能发生,prop4是在结果之内,我怎么能a这是否无效? prop4不是正在序列化的List<A>的一部分。

回答

5

发生这种情况是因为您在AList中存储了指向B对象实例的指针。当你做了“new B(){prop1 =”1“,prop2 =”2“,prop3 =”3“,prop4 =”4“}”你创建了一个B对象实例。 当序列化器反映存储在AList中的对象时,它会找到一个实际的B对象实例,因为您没有更改B对象实例,只将其存储在AList中。编译器允许你这样做,因为继承链允许它,但B对象实例没有改变,那么它是一个B对象实例,无论你存储在哪里。

而不是做的:

List<A> AList = BList.Cast<A>().ToList(); 

务必:

List<A> AList = BList.Select(b => new A() 
{ prop1 = b.prop1, prop2 = b.prop2, prop3 = b.prop3 }) 
.ToList(); 

这将在BList

+2

你知道你可以[编辑]你的答案? – rene

+1

这个工程,但有很多属性 - 是不是有一个更简单的方法? – c0rd

+1

answer edited;;) –

1

每个B实例创建一个新的A例如,如果你还没有自己做这些事正如其中一条评论中提到的那样,这里有一个我弄乱的代码。我还没有和AutoMapper一起工作过一段时间,所以我不记得如何绘制List<T>类型。无论如何,这里是小提琴:

var list = new List<B> { new B { prop1 = "1", prop2 = "2", prop3 = "3", prop4 = "4" } }; 
Mapper.Initialize(i => i.CreateMap<B, A>()); 
using (var stream = new FileStream(@"output.xml", FileMode.Create)) 
{ 
    var serializer = new DataContractSerializer(typeof(List<A>)); 
    serializer.WriteObject(stream, list.Select(i => Mapper.Map<A>(i)).ToList()); 
} 
1

DataContractResolver允许您自定义如何解决DataContract。在这种情况下,您只需要将子类型解析为基类型。

以下代码来自此博客文章。

https://blogs.msdn.microsoft.com/youssefm/2009/06/05/configuring-known-types-dynamically-introducing-the-datacontractresolver/

public class DeserializeAsBaseResolver : DataContractResolver 
{ 
    public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace) 
    { 
     return knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace); 
    } 

    public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver) 
    { 
     return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ?? declaredType; 
    } 
} 

根据框架,通过上面的类到datacontract串行器,它应该给你你需要的结果。

DataContractSerializer ser = new DataContractSerializer(typeof(List<A>));), null, Int32.MaxValue, false, false, null, new DeserializeAsBaseResolver()); 
1

在C#中向下转换的一种简单方法是序列化子代,然后将其反序列化为父代。

List<B> BList = new List<B>(); 
BList = new List<B>() { new B() { prop1 = "1", prop2 = "2", prop3 = "3", prop4 = "4" } }; 
var serializedChildList = JsonConvert.SerializeObject(BList); 
List<A> AList = JsonConvert.DeserializeObject<List<A>>(serializedChildList); 
DataContractSerializer ser = new DataContractSerializer(typeof(List<A>)); 
FileStream fs = new FileStream(@"C:\temp\AResult.xml", FileMode.Create); 
using (fs) 
{ 
    ser.WriteObject(fs, AList); 
} 

输出样本:

<ArrayOfA xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 
    <A> 
    <prop1>1</prop1> 
    <prop2>2</prop2> 
    <prop3>3</prop3> 
    </A> 
</ArrayOfA>