2016-09-21 16 views
7

tôi có 2 lớpđầu ra không hợp lệ với lớp kế thừa

[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; } 
} 

và phương pháp sau:

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); 
} 

mà viết này đến tập tin 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> 

Làm thế nào có thể xảy ra, rằng prop4 nằm trong kết quả và làm cách nào tôi có thể void này? prop4 không phải là một phần của List<A> đang được đăng.

Trả lời

5

Điều đó xảy ra vì bạn đang lưu trữ trong ALIST con trỏ đến cá thể đối tượng B. Khi bạn đã làm "mới B() {prop1 =" 1 ", prop2 =" 2 ", prop3 =" 3 ", prop4 =" 4 "}" bạn đã tạo một cá thể đối tượng B. Khi trình tuần tự phản ánh đối tượng được lưu trữ trong ALIST, nó tìm thấy một cá thể đối tượng B thực tế, vì bạn đã thay đổi thể hiện đối tượng B, bạn chỉ lưu nó trong AList. Trình biên dịch cho phép bạn làm điều đó bởi vì chuỗi thừa kế cho phép nó nhưng cá thể đối tượng B không thay đổi, sau đó nó là một cá thể đối tượng B không có vấn đề nơi bạn lưu trữ nó.

Thay vì thực hiện:

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(); 

Điều đó sẽ tạo ra một mới Một ví dụ cho mỗi trường hợp B trong BList

+2

bạn biết bạn có thể [sửa] câu trả lời của bạn? – rene

+1

hoạt động nhưng có rất nhiều thuộc tính - không có cách nào dễ dàng hơn? – c0rd

+1

answer edited ..;) –

1

Nếu bạn không làm điều đó cho mình chưa như đã đề cập trong một trong các bình luận, đây là một đoạn mã nhỏ mà tôi không thích. Tôi đã không làm việc với AutoMapper trong một thời gian, vì vậy tôi không thể nhớ và làm việc ra làm thế nào để bản đồ List<T> loại. Anyways, đây là fiddle:

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 cho phép bạn tùy chỉnh cách DataContract có thể được giải quyết. Trong trường hợp này, bạn chỉ muốn loại phụ được giải quyết làm loại cơ sở.

Mã sau đây là từ bài đăng trên blog này.

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

Tùy thuộc vào khuôn khổ, vượt qua lớp trên vào serializer DataContract và nó sẽ cho bạn những kết quả mà bạn cần.

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

Cách đơn giản để downcast trong C# là tuần tự hóa con và sau đó deserialize nó vào phụ huynh.

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); 
} 

mẫu đầu ra:

<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> 
Các vấn đề liên quan