所以我在玩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的方法吗?
您已经发现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>
的自定义集合所代替(演示小提琴#2IList<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>
之间的区别是前者实现了旧的非泛型接口AxisExceptionActionEnumCollection
和IList
,也许缺少对集合的非泛型访问会导致序列化程序出现问题?为了测试这一点,我为您的集合实现了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) }
。