代码之家  ›  专栏  ›  技术社区  ›  coding4fun

在运行时强制转换为泛型类型

  •  0
  • coding4fun  · 技术社区  · 14 年前

    好吧,我认为这是不可能的,所以我想我会要求确保。我正在创建一个函数,它反映类中的属性,并将它们添加到我拥有的这个数据结构中。有些属性是泛型类型。

    所以说我们有 DataType(Of T) 那有 .Value 类型的属性 T :

    Dim properties = GetType(MyType).GetFields(Reflection.BindingFlags.Public Or _
                                               Reflection.BindingFlags.Instance)
    For Each prop As fieldinfo In properties
       Collection.Add(prop.Name,prop.GetValue(poco))
    Next
    

    collection.Add 对于基本类型( Integer , String 等等……)我只想添加类型…但在一般情况下,我想添加 DataType(Of T).Value . 我希望有一些工作,但我认为没有办法,因为 T 不能在编译时确定对吗?理想的 DirectCast(prop.getvalue(poco), DataType(Of T)).Value 可能的。这是您希望在.NET 4.0中出现更多动态的时候。

    2 回复  |  直到 14 年前
        1
  •  1
  •   stakx - no longer contributing Saravana Kumar    14 年前

    我刚刚想到我可能误读了你的问题。因此,我的另一个回答。

    通过引入允许访问某些 Value 财产:

    Public Interface IHasValue
        Public ReadOnly Property Value As Object
    End Interface
    

    接下来,确保 DataType(Of T) 类实现此接口。这意味着每个 DataType(t) 对象(无论具体类型 T 也是) IHasValue ,您可以用 TypeOf(…) Is IHasValue :

    Public Class DataType(Of T) : Implements IHasValue
    
        Public Value As T
    
        Public ReadOnly Property UntypedValue As Object Implements IHasValue.Value
            Get
                Return Me.Value
            End Get
        End Property
    
    End Class
    

    (这个复制品 价值 有两个原因:第一,当 DataType(Of T).Value 是字段而不是属性,其次是因为它们的类型不同。)

    然后,在用字段填充集合的地方,可以检查特定字段是否是 DataType(t) (如果是这样,打开 价值 通过执行以下操作:

    Dim value As Object = prop.GetValue(poco)
    
    If TypeOf(value) Is IHasValue Then         ' <- is value a DataType(Of T) ?    '
        value = CType(value, IHasValue).Value  ' <- if so, unwrap the value        '
    End If
    
    Collection.Add(prop.Name, value)
    

    这可能比我的其他答案更符合你的要求,但让我强调一下:

    If TypeOf(…) Is … Then … 是代码气味 . 也许您应该重新考虑您的代码并研究涉及多态性的解决方案。

        2
  •  0
  •   stakx - no longer contributing Saravana Kumar    14 年前

    第一, 我对你想做什么的假设是:

    1. 你有一个叫 poco 具有类型 MyType .

    2. MyType 具有不同类型的字段,因此您认为需要泛型。

    3. 您有一个名为的键值对集合 Collection ,可能有类型 Dictionary(Of String, Object) ?

    4. 你想把所有的 POCO 的字段(即其名称和值)到 收藏 .


    侧节点: 您将字段与属性混合在一起:您的代码在字段上操作(通过调用 GetFields 当你的问题文本提到属性时。他们不是一回事!


    第二, 关于集合和静态类型系统的一些基本事实:

    • 非类型化集合(其中项属于类型 Object )可以在其中存储各种值。

    • 类型化集合(其中项属于更具体的类型,例如 T )只能存储具有类型的值 T 或派生自 T .


    第三, 以上结论:

    • 在你的情况下, 收藏 必须是非类型化集合,如果确实如此 POCO (具有类型) MyType )具有不同类型的字段。

    • 在这种情况下,泛型实际上根本帮不上你,因为这不是泛型的作用。当您想要定义 操作 (即方法、行为)以相同的方式工作,不管他们在处理什么类型的对象。

      例如, List(Of T) 定义一个集合类型,不管其类型如何,该集合类型的工作方式都相同 T 是。但这并不意味着你可以在 (t)表 ,因为一旦实例化此类型-例如, Dim xs As New List(Of String) - T 将固定到特定类型- String -,最后得到一个只接受此类型值的类型化集合。

      因此,再次说明:如果需要存储不同类型对象的集合,请选择 对象 作为值类型,而不是尝试查找涉及泛型的解决方案。


    也就是说,有 另一个解决方案:多态性 .

    如果您希望代码根据值的类型以不同的方式处理值,那么多态性就是解决方法:

    • 首先,定义接口或抽象基类(例如 DataType 不过,我强烈建议您选择一个更为不言自明的名字!)它指定可以对值执行什么操作。

    • 第二,类型 收藏 作为 Dictionary(Of String, DataType) . 这意味着只有类型的对象 数据类型 或者从中派生的任何内容都可以进入集合。

    • 第三,派生/实现 数据类型 为特定类型指定行为。

    有一个美好的地方 slide show called Conditionals and Polymorphism 这可能是这里感兴趣的。


    边注: 最后但并非最不重要的是,你 可以 查找泛型类型参数的类型: TypeOf(T) .