Vấn đề đã được giải quyết!
OK, vì vậy cuối cùng tôi đã đến được đó (phải thừa nhận rằng có rất nhiều sự giúp đỡ từ đây !).
Vì vậy, tóm tắt:
Bàn thắng:
- Tôi không muốn đi xuống tuyến đường XmlInclude do đau đầu về bảo trì.
- Khi một giải pháp được tìm thấy, tôi muốn nó nhanh chóng được triển khai trong các ứng dụng khác.
- Có thể sử dụng các bộ sưu tập các kiểu Trừu tượng, cũng như các thuộc tính trừu tượng riêng lẻ.
- Tôi thực sự không muốn bận tâm đến việc phải làm những việc "đặc biệt" trong các lớp bê tông.
Các vấn đề đã xác định / Điểm cần lưu ý:
- XmlSerializer thực hiện một số phản ánh khá thú vị, nhưng nó rất hạn chế khi nói đến các kiểu trừu tượng (tức là nó sẽ chỉ hoạt động với các thể hiện của chính kiểu trừu tượng, không phải các lớp con).
- Các trình trang trí thuộc tính Xml xác định cách XmlSerializer xử lý các thuộc tính mà nó tìm thấy. Loại vật lý cũng có thể được chỉ định, nhưng điều này tạo ra sự kết hợp chặt chẽ giữa lớp và bộ nối tiếp (không tốt).
- Chúng ta có thể triển khai XmlSerializer của riêng mình bằng cách tạo một lớp triển khai IXmlSerializable .
Giải pháp
Tôi đã tạo một lớp chung, trong đó bạn chỉ định kiểu chung là kiểu trừu tượng mà bạn sẽ làm việc. Điều này cung cấp cho lớp khả năng "dịch" giữa kiểu trừu tượng và kiểu cụ thể vì chúng ta có thể mã hóa quá trình đúc (tức là chúng ta có thể nhận được nhiều thông tin hơn XmlSerializer có thể).
Sau đó, tôi đã triển khai giao diện IXmlSerializable , giao diện này khá đơn giản, nhưng khi tuần tự hóa, chúng tôi cần đảm bảo rằng chúng tôi ghi loại lớp cụ thể vào XML, vì vậy chúng tôi có thể truyền nó trở lại khi hủy tuần tự hóa. Điều quan trọng cần lưu ý là nó phải có đầy đủ điều kiện vì các tập hợp mà hai lớp nằm trong có thể khác nhau. Tất nhiên có một chút kiểm tra kiểu và những thứ cần phải diễn ra ở đây.
Vì XmlSerializer không thể truyền, chúng tôi cần cung cấp mã để làm điều đó, vì vậy toán tử ngầm sau đó bị quá tải (tôi thậm chí chưa bao giờ biết bạn có thể làm điều này!).
Mã cho AbstractXmlSerializer là:
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
namespace Utility.Xml
{
public class AbstractXmlSerializer<AbstractType> : IXmlSerializable
{
public static implicit operator AbstractType(AbstractXmlSerializer<AbstractType> o)
{
return o.Data;
}
public static implicit operator AbstractXmlSerializer<AbstractType>(AbstractType o)
{
return o == null ? null : new AbstractXmlSerializer<AbstractType>(o);
}
private AbstractType _data;
public AbstractType Data
{
get { return _data; }
set { _data = value; }
}
public AbstractXmlSerializer()
{
}
public AbstractXmlSerializer(AbstractType data)
{
_data = data;
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
string typeAttrib = reader.GetAttribute("type");
if (typeAttrib == null)
throw new ArgumentNullException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
"' because no 'type' attribute was specified in the XML.");
Type type = Type.GetType(typeAttrib);
if (type == null)
throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
"' because the type specified in the XML was not found.");
if (!type.IsSubclassOf(typeof(AbstractType)))
throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
"' because the Type specified in the XML differs ('" + type.Name + "').");
reader.ReadStartElement();
this.Data = (AbstractType)new
XmlSerializer(type).Deserialize(reader);
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
Type type = _data.GetType();
writer.WriteAttributeString("type", type.AssemblyQualifiedName);
new XmlSerializer(type).Serialize(writer, _data);
}
#endregion
}
}
Vì vậy, từ đó, làm cách nào để chúng ta yêu cầu XmlSerializer hoạt động với bộ tuần tự của chúng ta thay vì mặc định? Chúng ta phải chuyển kiểu của mình trong thuộc tính kiểu thuộc tính Xml, ví dụ:
[XmlRoot("ClassWithAbstractCollection")]
public class ClassWithAbstractCollection
{
private List<AbstractType> _list;
[XmlArray("ListItems")]
[XmlArrayItem("ListItem", Type = typeof(AbstractXmlSerializer<AbstractType>))]
public List<AbstractType> List
{
get { return _list; }
set { _list = value; }
}
private AbstractType _prop;
[XmlElement("MyProperty", Type=typeof(AbstractXmlSerializer<AbstractType>))]
public AbstractType MyProperty
{
get { return _prop; }
set { _prop = value; }
}
public ClassWithAbstractCollection()
{
_list = new List<AbstractType>();
}
}
Ở đây bạn có thể thấy, chúng ta có một bộ sưu tập và một thuộc tính duy nhất đang được hiển thị và tất cả những gì chúng ta cần làm là thêm tham số có tên kiểu vào khai báo Xml, thật dễ dàng! : D
LƯU Ý: Nếu bạn sử dụng mã này, tôi thực sự đánh giá cao lời cảm ơn. Nó cũng sẽ giúp thu hút nhiều người hơn đến với cộng đồng :)
Bây giờ, nhưng không chắc phải làm gì với các câu trả lời ở đây vì tất cả họ đều có chuyên gia và phản ứng của mình. Tôi sẽ nâng cấp những thứ mà tôi cảm thấy hữu ích (không xúc phạm đến những thứ không có ích) và đóng nó lại khi tôi có đại diện :)
Vấn đề thú vị và niềm vui tốt để giải quyết! :)