我有一个这样的对象:
public partial class CableApplication : StateObject
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public CableApplication()
{
this.CableProperties = new HashSet<CableProperty>();
}
public int Id { get; set; }
public int ProjectId { get; set; }
public string Application { get; set; }
public byte[] ts { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<CableProperty> CableProperties { get; set; }
public virtual Project Project { get; set; }
}
在数据库优先的 Visual Studio C# 项目中自动在
.edmx
文件中创建。我想将 CableApplication
的所有数据导出到 XML 文件中。
我在服务中编写了这段代码:
public string ExportToXml<T>(T obj)
{
using (var stringwriter = new System.IO.StringWriter())
{
TextWriter writer = new StreamWriter(@"d:\\temp\\check.xml");
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(stringwriter, obj);
writer.Close();
return stringwriter.ToString();
}
}
前端项目中的这段代码:
private void exporToXMLToolStripMenuItem_Click(object sender, EventArgs e)
{
using (ICableService client = new CableService())
{
var applications = client.GetCableApplications(searchList.ToArray(), null, "").ToList(); // I get the list of cable Applications . works fine
var str = client.ExportToXml(applications);
}
}
但是我收到以下错误:
无法序列化类型“System.Collections.Generic.ICollection`1[[Cable1Layer.Domain.CableProperty,Cable1Layer.Domain,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”的成员“Cable1Layer.Domain.CableApplication.CableProperties” ]]',请参阅内部异常以获取更多详细信息
存在反映类型“Cable1Layer.Domain.CableApplication”的错误
我应该如何序列化这个对象?
最里面的错误消息(您的问题中未显示)是不言自明的:
System.NotSupportedException:无法序列化
类型的成员CableApplication.CableProperties
因为它是一个接口。ICollection<CableProperty>
XmlSerializer
无法序列化接口,因为它们不是具体类型,无法在反序列化期间构造。更多请看
[XmlIgnore]
标记原始属性,但是由于您的类是从 .edmx 文件自动生成的,您可能不想修改任何自动属性- 生成的代码。因此你可以做的是:
CableApplication
作为 partial 类生成的事实,在手动创建的部分文件中添加可序列化的代理属性。XmlAttributeOverrides
抑制不可序列化接口属性的序列化。为此,首先按如下方式扩展
CableProperties
:
public partial class CableApplication
{
public CableProperty [] CablePropertiesArray
{
get { return CableProperties.ToArray(); }
set
{
CableProperties.Clear();
if (value != null)
{
foreach (var item in value)
CableProperties.Add(item);
}
}
}
}
然后添加以下
XmlSerializer
工厂:
public static class XmlSerializerFactory
{
readonly static object lockObject = new object();
readonly static Dictionary<Type, XmlSerializer> SerializerDictionary = new Dictionary<Type, XmlSerializer>();
public static XmlSerializer CreateSerializer(Type type)
{
lock (lockObject)
{
XmlSerializer serializer;
if (SerializerDictionary.TryGetValue(type, out serializer))
return serializer;
var overrides = new XmlAttributeOverrides()
.AddCableApplicationOverrides()
// Add customizations for other types as needed here.
;
SerializerDictionary.Add(type, serializer = new XmlSerializer(type, overrides));
return serializer;
}
}
static XmlAttributeOverrides AddCableApplicationOverrides(this XmlAttributeOverrides overrides)
{
overrides.Add(typeof(CableApplication),
"CableProperties", // Use nameof(CableApplication.CableProperties) if available in your C# version
new XmlAttributes { XmlIgnore = true });
overrides.Add(typeof(CableApplication),
"CablePropertiesArray", // Use nameof(CableApplication.CablePropertiesArray) if available in your C# version
new XmlAttributes { XmlArray = new XmlArrayAttribute { ElementName = "CableProperties" } }); // Use nameof(CableApplication.CableProperties) if available in your C# version
return overrides;
}
}
最后修改
ExportToXml<T>(T obj)
以使用序列化器工厂:
public string ExportToXml<T>(T obj)
{
using (var stringwriter = new System.IO.StringWriter())
{
// You never actually write anything to the StreamWriter so I'm not sure what is going in here.
// I commented this code out since U don't have a d:\temp\check.xml file
//TextWriter writer = new StreamWriter( @"d:\\temp\\check.xml");
var serializer = XmlSerializerFactory.CreateSerializer(typeof(T));
serializer.Serialize(stringwriter, obj);
//writer.Close();
return stringwriter.ToString();
}
}
请注意,使用
XmlAttributeOverrides
构造序列化器时,需要静态缓存并重用序列化器,原因请参见 使用 StreamReader 和 XmlSerializer 的内存泄漏中所述。
演示小提琴在这里。