如何识别哪个类成员导致XmlSerializer出现问题

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

所以我在玩XmlSerializer,遇到了一些挑战。我有一个第三方XML文件,所以我受到了一个我不太喜欢的XML模式的约束。我想尝试从此XML到VBA实质上执行代理,所以我需要通过COM。

我设法使一些类正常工作,本质上是使用XSD2(CodeDom)将XML Schema转换为一组类,并操纵C#类以使用IList<>实现类。我认为这就是问题所在。我从几个类开始做起,并且运行良好,此后我通过CodeDom进行了介绍,现在在335个类/枚举领域中可以处理一些事情。

我得到的例外是在线

XmlSerializer serializer = new XmlSerializer(typeof(L5XSchema.RSLogix5000Content));

并且例外是:'CDF15337,DDB176069:同样在带有XmlAttributeAttribute的whidbey IEnumerable成员中失败'(以及指向该异常的唯一在线参考的链接,我可以找到https://github.com/microsoft/referencesource/blob/master/System.Xml/System/Xml/Serialization/XmlSerializationWriterILGen.cs

有人知道“ whidbey”参考是关于什么的吗?

[非常感谢,我已经确定了这个问题,这要归功于IEnumerable XmlAttributeAttribute部分。确实是这样。并将它们转换回Enum []允许构建XmlSerializer实例。此部分的XML模式(属性之一)如下所示:

<xs:attribute name="CIPAxisExceptionAction" use="optional">
  <xs:simpleType>
    <xs:list itemType="AxisExceptionActionEnum" />
  </xs:simpleType>
</xs:attribute>

没有人知道一种利用诸如IList<>之类的方式来获取XML属性值的方法吗?

。NET Framework示例问题:https://dotnetfiddle.net/Ws5VMI.NET Core示例问题:https://dotnetfiddle.net/ShO5UX

我目前仍在跳几圈,以根据模式使类对XmlSerializer感到满意。也对COM感到满意。这意味着没有可识别的通用集合,因此我的所有List<>成员都需要包装在IList<>实现包装器类中,才能通过COM屏障。处理派生类时非常烦人。

没有人知道一种将C#中的通用集合轻松代理到COM的方法吗?

c# com xmlserializer
1个回答
1
投票

您已经发现XmlSerializer的代码生成算法中似乎有个错误,特别是对于标有[XmlAttribute]的枚举的自定义集合,它们没有实现非通用接口System.Collections.ICollection]。解决方法似乎是在自定义集合上显式实现此接口。

详细如下。假设我们有如下类型:

System.Collections.ICollection

当序列化为XML时,该属性已成功序列化为包含如下空格分隔值序列的字符串(演示小提琴#1 public class RSLogix5000Content { [XmlAttribute] public List<AxisExceptionActionEnum> CIPAxisExceptionAction { get; set; } } public enum AxisExceptionActionEnum { Default = 0, Value1 = (1<<0), Value2 = (1<<1) } :]]

here

但是,如果<RSLogix5000Content CIPAxisExceptionAction="Value1 Value2 Value1" /> 被实现为List<AxisExceptionActionEnum>的自定义集合所代替(演示小提琴#2 IList<AxisExceptionActionEnum>:]]

here

然后抛出了一个难以理解的异常:

public class RSLogix5000Content
{
    [XmlAttribute]
    public AxisExceptionActionEnumCollection CIPAxisExceptionAction { get; set; }
}

public enum AxisExceptionActionEnum
{
    Default = 0,
    Value1 = (1<<0),
    Value2 = (1<<1)
}

public class AxisExceptionActionEnumCollection : IList<AxisExceptionActionEnum>
{
    private System.Collections.Generic.List<AxisExceptionActionEnum> axisExceptionActionEnumField = new System.Collections.Generic.List<AxisExceptionActionEnum>();

    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public AxisExceptionActionEnum this[int index] {
        get {
            return ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField))[index];
        }
        set {
            ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField))[index] = value;
        }
    }

    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public int Count {
        get {
            return ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).Count;
        }
    }

    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public bool IsReadOnly {
        get {
            return ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).IsReadOnly;
        }
    }

    public void Add(AxisExceptionActionEnum item) {
        ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).Add(item);
    }

    public void Clear() {
        ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).Clear();
    }

    public bool Contains(AxisExceptionActionEnum item) {
        return ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).Contains(item);
    }

    public void CopyTo(AxisExceptionActionEnum[] array, int arrayIndex) {
        ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).CopyTo(array, arrayIndex);
    }

    public int IndexOf(AxisExceptionActionEnum item) {
        return ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).IndexOf(item);
    }

    public void Insert(int index, AxisExceptionActionEnum item) {
        ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).Insert(index, item);
    }

    public bool Remove(AxisExceptionActionEnum item) {
        return ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).Remove(item);
    }

    public void RemoveAt(int index) {
        ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).RemoveAt(index);
    }

    public System.Collections.Generic.IEnumerator<AxisExceptionActionEnum> GetEnumerator() {
        return ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return ((System.Collections.Generic.IList<AxisExceptionActionEnum>)(this.axisExceptionActionEnumField)).GetEnumerator();
    }
}

为什么会发生这种情况?好吧,System.NotSupportedException: Also fail in IEnumerable member with XmlAttributeAttribute at System.Xml.Serialization.XmlSerializationWriterILGen.WriteMember(SourceInfo source, AttributeAccessor attribute, TypeDesc memberTypeDesc, String parent) at System.Xml.Serialization.XmlSerializationWriterILGen.WriteStructMethod(StructMapping mapping) at System.Xml.Serialization.XmlSerializationWriterILGen.GenerateMethod(TypeMapping mapping) at System.Xml.Serialization.XmlSerializationILGen.GenerateReferencedMethods() at System.Xml.Serialization.XmlSerializationWriterILGen.GenerateEnd() at System.Xml.Serialization.TempAssembly.GenerateRefEmitAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace) at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location) at System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace, String location) at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace) at System.Xml.Serialization.XmlSerializer..ctor(Type type) List<AxisExceptionActionEnum>之间的区别是前者实现了旧的非泛型接口AxisExceptionActionEnumCollectionIList,也许缺少对集合的非泛型访问会导致序列化程序出现问题?为了测试这一点,我为您的集合实现了IList

ICollection

问题就解决了!演示小提琴#3 ICollection

注意:

  • 仅需要实现非通用public class AxisExceptionActionEnumCollection : IList<AxisExceptionActionEnum>, ICollection { // Remainder unchanged #region ICollection Members void ICollection.CopyTo(Array array, int index) { ((System.Collections.IList)(this.axisExceptionActionEnumField)).CopyTo(array, index); } int ICollection.Count { get { return Count; } } bool ICollection.IsSynchronized { get { return ((System.Collections.IList)(this.axisExceptionActionEnumField)).IsSynchronized; } } object ICollection.SyncRoot { get { return ((System.Collections.IList)(this.axisExceptionActionEnumField)).SyncRoot; } } #endregion } 接口,而不是非通用here

  • [ICollection非常乐意序列化仅通用集合,只要它被标记为IList而不是XmlSerializer

    [XmlElement]
  • 演示小提琴#4 [XmlAttribute]

  • 由于public class RSLogix5000Content { [XmlElement] public AxisExceptionActionEnumCollection CIPAxisExceptionAction { get; set; } } 甚至没有here方法,因此绝对感觉像是ICollection错误。您可能要向Microsoft报告问题,例如Add(object value)

  • 我有点惊讶,将枚举的集合序列化为属性会导致空格分隔的枚举值序列; XmlSerializer中的任何内容均不建议这样做。

  • 但是由于here枚举也被序列化为以空格分隔的枚举值序列,所以似乎尝试将标记枚举的列表序列化为XML属性也会失败,并且出现了无法理解的异常:

docs
[Flags]

演示小提琴#5 public class RSLogix5000Content { [XmlAttribute] public List<AxisExceptionActionEnum> CIPAxisExceptionAction { get; set; } } [Flags] public enum AxisExceptionActionEnum { Default = 0, Value1 = (1<<0), Value2 = (1<<1) }

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