0

我有一个从字符串表创建字典的例程。根据具体的应用,这些字符串可能表示整数(“123”)、浮点数(“12.3”)或字符串(“foo bar”),但任何有效类型在显式写入时都可以直接从字符串转换。例如,这很好用(VB.NET):

Class IntStrDict
    Sub Add()
        Dim k As String = "123"
        Dim v As String = "foo bar"
        Dim d As New Dictionary(Integer, String)
        d.Add(k, v)
    End Sub
End Class

但我真的很想让这段代码通用,所以我重写为:

Class PairDict(Of TKey, TValue)
    Sub Add(k As TKey, v As TValue)
        Dim k As String = "123"
        Dim v As String = "foo bar"
        Dim d As New Dictionary(TKey, TValue)
        d.Add(k, v)
    End Sub
End Class

但这不起作用,因为 .NET 不知道可以将 String 直接转换为 TKey 或 TValue。有没有像 CastableFrom 这样的接口,我可以在其中声明这样的类?

Class PairDict(Of TKey As CastableFrom(Of String), TValue As CastableFrom(Of String))
4

2 回答 2

0

这个问题中想出来:CTypeDynamic(仅限.NET 4.0+)。这不起作用:

Class PairDict(Of TKey, TValue)
    Sub Add(k As TKey, v As TValue)
        Dim k As String = "123"
        Dim v As String = "foo bar"
        Dim d As New Dictionary(TKey, TValue)
        d.Add(CType(k, TKey), CType(v, TValue))
    End Sub
End Class

...但这确实:

Class PairDict(Of TKey, TValue)
    Sub Add(k As TKey, v As TValue)
        Dim k As String = "123"
        Dim v As String = "foo bar"
        Dim d As New Dictionary(TKey, TValue)
        d.Add(CTypeDynamic(Of TKey)(k), CTypeDynamic(Of TValue)(v))
    End Sub
End Class

这是一个有用的示例,说明有人可能会使用此功能做什么:

Public Class DictionaryGenerator(Of TKey, TValue)
    Public Function Generate(path As String, Optional excludeheader As Boolean = True) As Dictionary(Of TKey, TValue)
        Dim d As New Dictionary(Of TKey, TValue)

        Dim r As New Microsoft.VisualBasic.FileIO.TextFieldParser(path)
        r.TextFieldType = FileIO.FieldType.Delimited
        r.SetDelimiters(",")
        r.TrimWhiteSpace = True
        Dim csvline As String()
        If excludeheader Then r.ReadLine()
        While Not r.EndOfData
            csvline = r.ReadFields()
            d.Add(CTypeDynamic(Of TKey)(csvline(0)), CTypeDynamic(Of TValue)(csvline(1)))
        End While
        r.Close()

        Return d
    End Function
End Class
于 2013-01-11T00:29:11.190 回答
0

接口类型旨在对已经存在的实例进行操作。因此,类似的接口IConvertableTo(Of Out TDest)表达了一个有意义的概念:如果一个对象具有Foo实现的类型,那么一个对象IConvertable(Of Out Bar)将具有可以执行转换的东西。相比之下,IConvertableFrom(In TSrc)它就不太好用了,因为直到有一个实现它的对象才能使用该接口;如果生成这样一个对象的唯一方法是通过接口,那就是先有鸡还是先有蛋的问题。

有几个解决方案。可以有一个 type IConverter(In TSrc, Out TDest),并且有需要能够执行转换的方法接受该类型的实例。或者,如果一个类型允许创建“空白”然后“填充”实例,则可以使用{New,ILoadableFrom(In TSrc)}. 这将允许类似:

Shared Function Convert(Of TSource, TDest As {New, ILoadableFrom(TSource)})(Src as TSource)
    Dim Result = New TDest()
    Result.LoadFrom(TSource)
    Return Result
End Function

这种方法的最大缺点是它要求目标类型包含一个默认构造函数。另一个可能值得考虑的变体是要求作为合同问题,实现接口的每个类型都ICastableFrom(of T)必须包含一个静态方法Function CastFrom(T param) As [itsOwnType]。然后可以编写一个带有签名的静态方法,Function ICastableCast(Of TSrc, TDest)(src as TSrc) as TDest该方法将使用反射来查找静态方法TDest.CastFrom(param as TSrc) As TDest并调用它。如果反射只对每个 (TSrc,TDest) 对使用一次,那么这种方法可能会相当快。

于 2013-01-12T18:24:07.460 回答