.net - IEnumerable(of String) 被 XmlSerializer 忽略
问题描述
对于我的一个对象,我需要做一些向后/向前兼容的技巧,以便在不同版本共存并共享相同配置文件时每个人都感到高兴。
我尝试的最后一个技巧是有一个桥接集合,它使用IEnumerable(Of String)
. 我的问题是我无法XmlSerializer
识别我的自定义收藏。我查看了生成代码的序列化程序代码,一切似乎都很好。无论我做什么,只要我使用我的自定义集合ListeCategories
,最终都会以Unsupported
. 如果我使用 basic List(Of String)
,它可以工作,但我错过了逻辑。我错过了什么?
我还尝试了一个非通用自定义集合(在第二个代码片段中注释),但没有成功。
以下是主要对象和自定义集合的代码。请注意,自定义可枚举实现和附加Add
方法XmlSerializer
(根据MS Docs)。
XmlSerializer 对实现 IEnumerable 或 ICollection 的类进行特殊处理。实现 IEnumerable 的类必须实现采用单个参数的公共 Add 方法。Add 方法的参数必须与从 GetEnumerator 返回的值的 Current 属性返回的类型相同,或者该类型的基数之一。除了 IEnumerable 之外,实现 ICollection 的类(例如 CollectionBase)必须具有采用整数的公共 Item 索引属性(C# 中的索引器),并且必须具有整数类型的公共 Count 属性。Add 方法的参数必须与从 Item 属性返回的类型相同,或者是该类型的基数之一。对于实现 ICollection 的类,要序列化的值是从索引的 Item 属性中检索的,
Public Class OptionsSerializable
Public Sub New()
End Sub
<XmlAnyElement>
Public Property Unsupported As List(Of XmlElement)
<System.Xml.Serialization.XmlElement(ElementName:="ListeCategoriesExt")>
Public ReadOnly Property Categories As List(Of CategoryInfo)
Public ReadOnly Property ListeCategories As IEnumerable(Of String) = New EnumerableBridge(Of String, CategoryInfo)(_categories, Function(s) New CategoryInfo(s), Function(c) c.SearchTerm)
Public Property ServeurExchangeUrl As String
Public Property VersionExchange As String
Public Property AdresseBoitePartager As New List(Of String)
Public Property GroupingMasks As New List(Of String)
Public Property TFSLinks As New XmlSerializableDictionary(Of String, String)
Public Property EstAlertageActif As Boolean
Public Property Laps As Integer
Public Property NbErreursMaximum As Integer
Public Property DerniereVerification As Date
Public Property ListeEnvoi As String
Public Property DernierEnvoi As Date
Public Property LogonDernierEnvoi As String
Public Property IntervalEnvoiMinimum As Integer
End Class
'Public Class SpecificCollectionBridge
' Inherits CollectionBridge(Of String, CategoryInfo)
' Public Sub New(refCollection As IEnumerable(Of CategoryInfo))
' MyBase.New(refCollection, Function(s) New CategoryInfo(s), Function(c) c.SearchTerm)
' End Sub
'End Class
<Serializable>
Public Class EnumerableBridge(Of TSource, TTarget)
Implements IEnumerable(Of TSource)
Private _refCollection As IList(Of TTarget)
Private _converterTo As Func(Of TSource, TTarget)
Private _converterFrom As Func(Of TTarget, TSource)
Public Sub New()
End Sub
Public Sub New(refCollection As IList(Of TTarget), converterTo As Func(Of TSource, TTarget), converterFrom As Func(Of TTarget, TSource))
_refCollection = refCollection
_converterTo = converterTo
_converterFrom = converterFrom
End Sub
Public Sub Add(item As TSource) 'Implements ICollection(Of TSource).Add
_refCollection.Add(_converterTo(item))
End Sub
Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return GetEnumerator()
End Function
Public Function IEnumerableOfT_GetEnumerator() As IEnumerator(Of TSource) Implements IEnumerable(Of TSource).GetEnumerator
Return _refCollection.Select(_converterFrom).GetEnumerator()
End Function
End Class
解决方案
您在这里有几个问题:
您的属性
ListeCategories
必须声明为实际返回的具体类型,而不是接口。XmlSerializer
即使预先分配,也不会序列化声明为接口的属性。您的类型
EnumerableBridge(Of TSource, TTarget)
必须GetEnumerator() As IEnumerator(Of TSource)
直接实现(使用 nameGetEnumerator()
)并GetEnumerator() As IEnumerator
使用其他名称显式实现。在您的课程中,您执行相反的操作并显式实现泛型方法,这会导致一个奇怪的异常并抛出无用的消息:
[System.InvalidOperationException: To be XML serializable, types which inherit from IEnumerable must have an implementation of Add(System.Object) at all levels of their inheritance hierarchy. EnumerableBridge`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[CategoryInfo, 58be8a1c-a824-4133-9ef8-b2552cccedab, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]] does not implement Add(System.Object).]
在这里演示问题的小提琴:https ://dotnetfiddle.net/PhaeZc
NotImplementedException()
您可以从 的无参数构造函数中抛出 aEnumerableBridge()
,因为XmlSerializer
实际上不会调用它。假设这个问题与您之前的问题.NET 相关 - 是否可以在同一个对象中同时使用 XmlAnyElementAttribute 和 XmlSerializer.UnknownElement 事件,您需要增强
EnumerableBridge.Add(item As TSource)
以检查CategoryInfo
传入的 a 是否SearchTerm
已经反序列化和添加,并且如果是这样,请不要添加重复项。否则,
ListeCategoriesExt
每次往返 XML 时,内容都会重复。在这里演示问题的小提琴:https ://dotnetfiddle.net/C0CUV4 。
由于
Action(Of IList(Of TTarget), TSource)
并且Func(Of TTarget, TSource)
不能正确序列化(通过BinaryFormatter
),我建议<Serializable>
从EnumerableBridge
.
因此你EnumerableBridge
应该看起来像:
' <Serializable> Removed since _converterFrom and _add are not really serializable
Public Class EnumerableBridge(Of TSource, TTarget)
Implements IEnumerable(Of TSource)
Private _refCollection As IList(Of TTarget)
Private _add As Action(Of IList(Of TTarget), TSource)
Private _converterFrom As Func(Of TTarget, TSource)
Sub New()
Throw New NotImplementedException()
End Sub
Public Sub New(refCollection As IList(Of TTarget), add As Action(Of IList(Of TTarget), TSource), converterFrom As Func(Of TTarget, TSource))
_refCollection = refCollection
_add = add
_converterFrom = converterFrom
End Sub
Public Sub Add(item As TSource) 'Implements ICollection(Of TSource).Add
_add(_refCollection, item)
End Sub
Public Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return GetEnumerator()
End Function
Public Function GetEnumerator() As IEnumerator(Of TSource) Implements IEnumerable(Of TSource).GetEnumerator
Return _refCollection.Select(_converterFrom).GetEnumerator()
End Function
End Class
并且OptionsSerializable
应该修改如下:
Public Class OptionsSerializable
Public Sub New()
End Sub
<XmlAnyElement>
Public Property Unsupported As List(Of XmlElement)
<System.Xml.Serialization.XmlElement(ElementName:="ListeCategoriesExt")>
Public ReadOnly Property Categories As List(Of CategoryInfo) = New List(Of CategoryInfo)
Shared Sub AddCategory(Categories as IList(Of CategoryInfo), Name as String)
If Not Categories.Any(Function(c) c.SearchTerm = Name) Then
Categories.Add(New CategoryInfo(Name))
End If
End Sub
Public ReadOnly Property ListeCategories As EnumerableBridge(Of String, CategoryInfo) = New EnumerableBridge(Of String, CategoryInfo)(_categories, AddressOf AddCategory, Function(c) c.SearchTerm)
' Remainder unchanged
演示小提琴在这里:https ://dotnetfiddle.net/bfYd1l
推荐阅读
- react-native - 我们如何在本机反应中自动滚动和自动循环平面列表
- python-3.x - 在 Python 中抓取后以正确的格式存储数据,对 csv 数据进行后处理
- c - C中的方法链接
- vue.js - 控制台上的 Vue 警告:组件渲染函数中可能存在无限更新循环
- java - 打印长数组的语法帮助
- javascript - kendoWindow 不会在子页面中正常弹出窗口
- google-chrome - 新的 Google 协作平台公告和最近的发布方法
- performance - JMeter如何从一组提取的值中随机选择
- azure - Azure AD 授权端点请求管理员同意
- python - Django点击获取主窗口的url