将对象导出到 XML 文件

问题描述 投票:0回答:1

我有一个这样的对象:

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”的错误

我应该如何序列化这个对象?

c# xml serialization
1个回答
0
投票

最里面的错误消息(您的问题中未显示)是不言自明的:

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 的内存泄漏中所述。

演示小提琴在这里

© www.soinside.com 2019 - 2024. All rights reserved.