2

インスタンスのプロパティで XML ドキュメントを作成したいと考えています。そのために、2 つの拡張機能を作成します。

<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

2 番目の方法は by の型に使用IEnumerable(Of T)し、最初の方法は他のすべての型に使用する必要があります。ButtonString、またはこのようなインスタンスで試してみると、Int32うまくいきます。ie のインスタンスでList(Of T)も、最初のメソッドが呼び出されます。IEnumerable(Of T)Tの拡張子の方が範囲が広いため、拡張子のforは無視されているようです。

List(Of T)拡張機能の使用を強制する可能性はありIEnumerable(Of T)ますか?

4

1 に答える 1

0

オーバーロードの「署名」Of Tには一般的な制約が含まれていないため、節で調整しAsても役に立たないようです。

単純な (非ジェネリック) インターフェイスの場合、オーバーロードが使用するクラスに最も近いものが選択されるという点で、同じ「問題」が発生します。

したがって、あるクラスでは、List(Of Integer)たとえば、2 つの署名がToXml(List(Of Integer))ToXml(IEnumerable(Of Integer))あるため、明らかに前者が選択され、完全に一致することに注意してください。

「最も具体的ではない」ためです。エラー、将来のコーダーが間違ったルーチンを呼び出したというヒントを与えることができる解決策すらありません。私が提案できる最善の方法は、リストになる可能性のあるオブジェクトにオーバーロードを使用しないことです:-(

すなわち持っているToXmlFromObject(Of T)(ByVal source As T)ToXmlFromList(Of T)(ByVal source As IEnumerable(Of T))

And, at runtime ( :-( ), you can use Reflection in ToXmlFromObjectto check for usage by 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)いくつかのエラー メッセージで示唆されているもう 1 つのオプションについても言及しておく必要がありますToXml(As IEnumerable(Of T))。つまり、バージョンが(Of ElementType)確実に呼び出されるように明示的にリストします。(実装ToXml(Of ElementType)(As IEnumerable(Of ElementType))している場合でも、これは失敗します。)SomeTypeIEnumerable(Of SomeType)


間違った答え

Tコメントで述べたように、IEnumerable(Of )キャストで別の型を指定する必要があるため、これは失敗します。

また、上記の両方の署名が同じであるため、で呼び出すToXmlIEnumerable(Of Anything)エラーが発生するため、これが失敗することに気付きました。 ...最も具体的ではありません。".

あなたの唯一の選択肢は、過負荷を手動で「強制」することだと思います。つまり、正確なケースでは、インターフェースが一致するかどうかを確認し、そのオーバーロードを呼び出します。

<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)
  ...
于 2013-07-01T15:26:14.417 に答える