无法序列化成员....因为它是一个接口

时间:2010-09-03 02:51:06

标签: c# xml-serialization

我一直有这个问题,一直把头发拉过来。我有以下错误:

  

异常详细信息:System.NotSupportedException:无法序列化类型System.Collections.Generic.IList`1 [[HannaPrintsDataAccess.CustomerAddress,HannaPrintsDataAccess,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]的成员HannaPrintsDataAccess.Customer.CustomerAddresses ]]因为它是一个界面。

     

来源错误:

     

第196行:客户客户= OperationsManager.Instance.CustomerService.GetCustomer(7);   197行:   第198行:字符串xml = OperationsManager.Instance.CustomerService.GetCustomerAddressesXml(CustomerAddress.FindAll());   199行:   第200行:订单订单= OperationsManager.Instance.OrderService.CreateOrderFromCart(xml);

     

源文件:c:\ HostingSpaces \ greetwus \ galadavetiye.com \ wwwroot \ HannaPrints \ HannaPrints \ WebUI \ CreateGreetingCard.aspx.cs Line:198

     

堆栈追踪:

     

[NotSupportedException:无法序列化类型为System.Collections.Generic.IList`1 [[HannaPrintsDataAccess.CustomerAddress,HannaPrintsDataAccess,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]]的成员HannaPrintsDataAccess.Customer.CustomerAddresses,因为它是一个界面。]

     

[InvalidOperationException:无法序列化'System.Collections.Generic.IList`1类型的成员'HannaPrintsDataAccess.Customer.CustomerAddresses'[[HannaPrintsDataAccess.CustomerAddress,HannaPrintsDataAccess,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null] ]',请参阅内部异常了解更多详情。]      System.Xml.Serialization.StructModel.CheckSupportedMember(TypeDesc typeDesc,MemberInfo成员,类型类型)+889917      System.Xml.Serialization.StructModel.GetPropertyModel(PropertyInfo propertyInfo)+132 ........

我已经将我的所有IList更改为List's以查看它是否可以执行任何操作,但事实上,在进行这些更改之后它甚至没有花费一秒钟加载,我猜测因为错误发生甚至在它到达之前部分。我检查了我的远程文件,看它是否正确上传,它是。

以下是代码:

using System;
using System.Collections.Generic; 
using Castle.ActiveRecord;
namespace HannaPrintsDataAccess { 
    public partial class Customer { 
        private IList _customerAddresses;


        public CustomerAddress GetPrimaryCustomerAddress()
        {
            foreach (CustomerAddress address in _customerAddresses)
            {
                if (address.IsPrimary)
                    return address;
            }
            return null;
        }


        [HasMany(typeof(CustomerAddress), ColumnKey = "CustomerId", Table = "Customer")]
        public virtual IList<CustomerAddress> CustomerAddresses
        {
            get
            {
                return this._customerAddresses;
            }
            set
            {
                this._customerAddresses = value;
            }
        }
    }
}

激活此代码时会发生错误:

protected void orderButton_Click(object sender, EventArgs e)
{
    Customer customer = OperationsManager.Instance.CustomerService.GetCustomer(7);

    string xml = OperationsManager.Instance.CustomerService.GetCustomerAddressesXml(CustomerAddress.FindAll());

    Order order = OperationsManager.Instance.OrderService.CreateOrderFromCart(xml);
    OperationsManager.Instance.CartService.MoveCart("MyDesigns");

    Response.Redirect("~/Customer/PayByCreditCard.aspx?orderGuid=" + order.OrderGuid);
}

CustomerAddress类:

using System.IO;
using System.Xml.Serialization;
using Castle.ActiveRecord;


namespace HannaPrintsDataAccess
{
public partial class CustomerAddress
{
    public string ToXml()
    {
        XmlSerializer serializer = new XmlSerializer(GetType());
        MemoryStream memoryStream = new MemoryStream();
        serializer.Serialize(memoryStream, this);
        memoryStream.Seek(0, SeekOrigin.Begin);
        return new StreamReader(memoryStream).ReadToEnd();
    }

    [BelongsTo("CustomerId")]
    public virtual Customer Customer { get; set; }
}
}

4 个答案:

答案 0 :(得分:22)

在您发布的代码中,CustomerAddresses的类型为IList<CustomerAdress>。那是一个界面。与错误消息一样,您无法序列化接口。

答案 1 :(得分:1)

在某些情况下,人们可能对序列化对象的所有字段不感兴趣。在这种情况下,从对象的序列化中显式排除字段的 C# 语法如下:

XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
XmlAttributes attrs = new XmlAttributes{ XmlIgnore = true };
attrOverrides.Add(type, member, attrs);   // "type" = type of the class that contains the member
XmlSerializer serializer = new XmlSerializer(obj.GetType(), attrOverrides);
[...]         

例如,排除,例如出于隐私原因,我们应该编写“obj”对象序列化中的“密码”字段:

attrOverrides.Add(obj.GetType(), "Password", attrs);

对于未在对象中直接声明而是继承的字段,“type”参数指的是声明该字段的祖先。例如,为了避免在 System.ComponentModel.Component 的后代对象中出现错误“无法序列化 System.ComponentModel.ISite 类型的成员 System.ComponentModel.Component.Site,因为它是一个接口 em>",使用的语法是:

attrOverrides.Add(typeof(System.ComponentModel.Component), "Site", attrs);

通常,XMLSerializer 无法序列化暴露接口类型字段的类的对象。然而,如果有人仍然想序列化(使用 XMLSerializer)这种类型的对象(例如出于日志原因)并且在序列化中忽略接口类型的字段没有问题,以下函数会自动忽略这种类型的字段(注意:当然最终结果将不是初始对象的序列化,而是序列化排除被忽略的部分,这不是一回事):

public static string Serialize<T>(T obj, bool ignoreInterfaceTypeFields = false, List<Tuple<Type, string>> ignoreTypeList = null)
{
    string retValue = string.Empty;

    try
    {
        XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
        XmlAttributes attrs = new XmlAttributes{ XmlIgnore = true };
        ignoreTypeList?.ForEach(t => attrOverrides.Add(t.Item1, t.Item2, attrs));    // ignore fields in ignoreTypeList
        
        if (ignoreInterfaceTypeFields)
        {
            foreach (var t in obj.GetType().GetProperties())
            {
                if (t.PropertyType.IsInterface)
                    if (attrOverrides[t.DeclaringType, t.Name] is null)
                        attrOverrides.Add(t.DeclaringType, t.Name, attrs);    // ignore interface type fields
            }
        }

        XmlSerializer serializer = new XmlSerializer(obj.GetType(), attrOverrides);
        using (var sw = new StringWriter())
        {
            using (XmlTextWriter writer = new XmlTextWriter(sw) { Formatting = Formatting.Indented })
            {
                serializer.Serialize(writer, obj);
                retValue = sw.ToString();
            }
        }
    }
    catch (Exception ex) { throw ex; }
    
    return retValue;
}


// declared in non-generic, non-nested static classes
public static string Serialize<T>(this T obj, bool ignoreInterfaceTypeFields = false, List<Tuple<Type, string>> ignoreTypeList = null)
{
    return Serialize<T>(obj, ignoreInterfaceTypeFields, ignoreTypeList);
}

这个Serialize方法可以不带参数调用:

sClient = client.Serialize();

或手动排除不需要的字段:

var ignoreTypeList = new List<Tuple<Type, string>>
{
    new Tuple<Type, string>(client.GetType(), "Password"),                       // unwanted field (directly declared in "Client" class)
    new Tuple<Type, string>(typeof(System.ComponentModel.Component), "Site")     // unwanted field (declared in "System.ComponentModel.Component" ancestor class of "Client" class)
};

sClient = client.Serialize(false, ignoreTypeList);

或排除不需要的字段和接口类型字段:

var ignoreTypeList = new List<Tuple<Type, string>>
{
    new Tuple<Type, string>(client.GetType(), "Password")                        // unwanted field (directly declared in "Client" class)
};

sClient = client.Serialize(true, ignoreTypeList);

注意:使用框架 4.7.2 或更高版本(或使用 System.ValueTuple nuget)可以使元组的语法更具可读性:

public static string Serialize<T>(T obj, bool ignoreInterfaceTypeFields = false, List<(Type type, string member)> ignoreTypeList = null)

和:

var ignoreTypeList = new List<(Type, string)> 
{
    new (client.GetType(), "Password"),                        
    new (typeof(System.ComponentModel.Component), "Site")
};

答案 2 :(得分:0)

以下选项因 XML 序列化程序失败:

public IList<CustomerAddresses> CustomerAddresses  { get; set; }
public IEnumerable<CustomerAddresses> CustomerAddresses  { get; set; }

使用如下数组:

public CustomerAddresses[] CustomerAddresses { get; set; }

以下作品但不是声纳/质量投诉:

public List<CustomerAddresses> CustomerAddresses  { get; set; }

答案 3 :(得分:-1)

不是您的问题的根源,但您需要

using (MemoryStream memoryStream = new MemoryStream())
{
    serializer.Serialize(memoryStream, this);
    memoryStream.Seek(0, SeekOrigin.Begin);
    using (StreamReader reader = new StreamReader(memoryStream))
    {
        return reader.ReadToEnd();
    }
}