【问题标题】:Overload extension methods of TT的重载扩展方法
【发布时间】:2013-04-08 21:31:48
【问题描述】:

我想通过实例的属性创建一个 XML 文档。为此,我编写了两个扩展。

<Extension()>
Public Function ToXml(Of T)(ByVal source As T) As XmlDocument
    Dim oXmlDocument As New XmlDocument
    oXmlDocument.AppendChild(oXmlDocument.CreateXmlDeclaration("1.0", "utf-8", Nothing))
    oXmlDocument.AppendChild(oXmlDocument.CreateElement(XmlConvert.EncodeName(source.GetType.ToString)))

    For Each Item As System.Reflection.FieldInfo In source.GetType.GetFields
        Dim oElement As XmlElement = oXmlDocument.CreateElement(Item.Name)
        oElement.Attributes.Append(oXmlDocument.CreateAttribute("Value")).Value = Item.GetValue(Nothing).ToString
        oXmlDocument.DocumentElement.AppendChild(oElement)
    Next

    Return oXmlDocument
End Function

<Extension()>
Public Function ToXml(Of T)(ByVal source As IEnumerable(Of T)) As XmlDocument
    Dim oXmlDocument As New XmlDocument
    oXmlDocument.AppendChild(oXmlDocument.CreateXmlDeclaration("1.0", "utf-8", Nothing))
    oXmlDocument.AppendChild(oXmlDocument.CreateElement(XmlConvert.EncodeName(source.GetType.ToString)))

    For Each Item As T In source
        oXmlDocument.DocumentElement.AppendChild(oXmlDocument.ImportNode(Item.ToXml.DocumentElement, True))
    Next

    Return oXmlDocument
End Function

第二种方法应该适用于IEnumerable(Of T) 的类型,第一种适用于所有其他类型。如果我尝试使用 ButtonStringInt32 或类似的实例,它可以正常工作。对于 List(Of T) 的实例,也将调用第一个方法。 IEnumerable(Of T) 的扩展似乎被忽略了,因为 T 的扩展范围更广。

是否有可能强制List(Of T) 使用IEnumerable(Of T) 的扩展名?

【问题讨论】:

标签: xml vb.net reflection types extension-methods


【解决方案1】:

overload "signature" 不包含通用约束,因此使用 As 子句调整 Of T 似乎没有帮助。

对于简单(非泛型)接口,会出现相同的“问题”,即选择与类最接近的匹配项供重载使用。

因此请注意,对于某些类,List(Of Integer) 说,两个签名是 ToXml(List(Of Integer))ToXml(IEnumerable(Of Integer)),因此它会清楚地选择前者,这是完全匹配的。

因为“不是最具体的”。错误,我什至没有解决方案可以让您向未来的编码人员提示他们调用了错误的例程。我能建议的最好的办法是不要对可以是列表的对象使用重载:-(

即有ToXmlFromObject(Of T)(ByVal source As T)ToXmlFromList(Of T)(ByVal source As IEnumerable(Of T))

而且,在运行时 (:-(),您可以在 ToXmlFromObject 中使用反射来检查 Enumerables 的使用情况。类似这样的内容(直接输入到 SO 文本框中):

Debug.Assert(GetType(T) Is GetType(String) _
    OrElse Not (From i In GetType(T).GetInterfaces() _
        Where i Is GetType(IEnumerable)).Any)

我还应该提到一些错误消息暗示的另一个选项:您可以继续重载ToXml(As T)ToXml(As IEnumerable(Of T)),但不要依赖隐含的重载。 IE。明确列出(Of ElementType) 以确保调用ToXml(Of ElementType)(As IEnumerable(Of ElementType)) 版本。 (当您确实让 SomeType 实现 IEnumerable(Of SomeType) 时,这仍然会失败。)


错误答案

正如我在 cmets 中提到的,这会失败,因为您想在 IEnumerable(Of ) 演员表中指定与 T 不同的类型。

另外我现在注意到这会失败,因为用IEnumerable(Of Anything) 调用ToXml 会出错,因为上面描述的两个签名是相同的,所以它会出现“重载解析失败,因为没有可访问的 'ToXml' 是最具体针对这些论点:...不是最具体的。...不是最具体的。”。

我认为您唯一的选择是在另一个方向手动“强制”重载;即在确切的情况下,检查接口是否匹配,并调用该重载:

<Extension()>
Public Function ToXml(Of T)(ByVal source As T) As XmlDocument
  Dim enumSource = TryCast(source, IEnumerable(Of T))
  If enumSource IsNot Nothing Then Return ToXml(enumSource)
  ...

【讨论】:

    猜你喜欢
    • 2012-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 2014-06-07
    • 1970-01-01
    相关资源
    最近更新 更多