【问题标题】:CastableFrom interface in .NET?.NET 中的 CastableFrom 接口?
【发布时间】:2013-01-11 00:29:11
【问题描述】:

我有一个从字符串表创建字典的例程。根据具体的应用,这些字符串可能表示整数(“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))

【问题讨论】:

    标签: .net vb.net string generics casting


    【解决方案1】:

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

    有几个解决方案。可以有一个类型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) 对只使用一次反射,那么这种方法可能会相当快。

    【讨论】:

    • 这是一个很好的观点(IConvertableFrom 在.NET 中没有真正意义,而 IConvertableTo 确实有意义),但我想在问题中实际使用假设的非工作代码,所以我认为我的上述答案更好地解决意图。但是,您的回答确实更好地解决了问题的标题——我应该停止假设我的问题在选择标题时会有特定类型的答案。我认为在上下文中对我的标题问题的严格回答是,无法在编译时指定泛型类型可以转换为另一种类型。需要动态检查
    • 基于反射的方法将允许使用类似于您在答案中发布的代码,而不需要在 .Net 4.0 之前不可用的动态功能。
    【解决方案2】:

    this question: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
    

    【讨论】:

      猜你喜欢
      • 2011-04-01
      • 2016-01-31
      • 2010-09-05
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多