T的重载扩展方法

时间:2013-04-16 12:57:48

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

我想通过实例的属性创建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)的扩展程序?

1 个答案:

答案 0 :(得分:0)

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

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

所以请注意,对于某些课程,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)),但不要依赖隐含的重载。即明确列出(Of ElementType)以确保调用ToXml(Of ElementType)(As IEnumerable(Of ElementType))版本。 (当SomeType实施IEnumerable(Of SomeType)时,这仍然会失败。)


错误回答

正如我在评论中提到的,这会失败,因为您要在T演员表中指定IEnumerable(Of )的其他类型。

此外,我现在注意到这会失败,因为使用ToXml调用IEnumerable(Of Anything)会出错,因为上面描述的两个签名都是相同的,因此错误“重载解析失败,因为无法访问” 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)
  ...