简体   繁体   English

在运行时转换为通用类型

[英]cast to generic type at runtime

Ok, i don't think this is possible so I thought I would ask to make sure. 好的,我认为这是不可能的,所以我想我要确保。 I'm in the process of creating a function which reflects over the properties in a class and adds them to this data structure I have. 我正在创建一个函数,该函数反映类中的属性并将它们添加到我拥有的此数据结构中。 Some of the properties are generic types. 一些属性是通用类型。

So say we have DataType(Of T) that has a .Value property of type T : 假设我们有一个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

In the collection.Add for primitive types ( Integer , String , etc.…) I just want to add the type... but in the case of generic I want to add the DataType(Of T).Value . collection.Add ,输入原始类型( IntegerString等),但是我只想添加类型...,但对于通用类型,我想添加DataType(Of T).Value I hope there is some work-around but I don't think there is a way because the type of T can not be determined at compile time right? 我希望有一些解决方法,但是我不认为有办法,因为无法在编译时确定T的类型,对吗? Ideally DirectCast(prop.getvalue(poco), DataType(Of T)).Value would be possible. 理想情况下, DirectCast(prop.getvalue(poco), DataType(Of T)).Value是可能的。 This is when you hoped even more dynamics appear than whats in .NET 4.0. 在这种情况下,您希望出现比.NET 4.0更多的动态特性。

It just occurred to me that I may have mis-read your question. 我刚发现我可能误解了您的问题。 Therefore another answer from me. 因此,我的另一个答案。

You can avoid the need to cast to a generic type (where you don't know the type parameter) at runtime by introducing a new interface that allows access to some Value property: 通过引入允许访问某些Value属性的新接口,可以避免在运行时强制转换为泛型类型(您不知道type参数)。

Public Interface IHasValue
    Public ReadOnly Property Value As Object
End Interface

Next, make sure your DataType(Of T) class implements this interface. 接下来,确保您的DataType(Of T)类实现了此接口。 This means that each DataType(Of T) object (no matter what concrete type T is) is also an IHasValue , and you will be able to check this with TypeOf(…) Is IHasValue : 这意味着每个DataType(Of 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

(This duplication of Value is necessary for two reasons: First it is necessary when DataType(Of T).Value is a field instead of a property, and second because they do not have the same type.) (由于两个原因,必须进行Value重复:首先,当DataType(Of T).Value时是必需的DataType(Of T).Value是一个字段而不是属性,其次,因为它们没有相同的类型。)

Then, where you fill your collection with fields, you can check whether a particular field is an DataType(Of T) (and if so, unwrap the Value from it) by doing the following: 然后,在用字段填充集合的地方,可以通过执行以下操作检查特定字段是否为DataType(Of T) (如果是,则从中解开Value ):

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)

This is probably more what you're after than my other answer, but let me emphasise this: 与我的其他答案相比,这可能是您所追求的更多,但是让我强调一下:

If TypeOf(…) Is … Then … is a code smell . If TypeOf(…) Is … Then …是代码气味 Perhaps you should re-think your code and investigate solutions involving polymorphism. 也许您应该重新考虑代码并研究涉及多态性的解决方案。

First, my assumptions about what you're attempting to do: 首先, 我对您要执行的操作的假设:

  1. You have some object named poco , having type MyType . 您有一个名为poco对象,其类型为MyType

  2. MyType has fields of different types, thus you think you need generics. MyType具有不同类型的字段,因此您认为您需要泛型。

  3. You have a key-value-pair collection named Collection , probably having type Dictionary(Of String, Object) ? 您有一个名为Collection的键-值对集合,可能具有Dictionary(Of String, Object)

  4. You want to transfer all of poco 's fields (ie., their names and values) to Collection . 您想将poco的所有字段(即它们的名称和值)转移到Collection


Side node: You are mixing up fields with properties: Your code operates on fields (by invoking GetFields ), while your question text speaks of properties. 侧节点:您正在将字段与属性混合:您的代码在字段上运行(通过调用GetFields ),而您的问题文本谈到了属性。 They are not the same thing! 它们不是同一件事!


Second, some fundamental facts about collections and the static type system: 第二, 关于集合和静态类型系统的一些基本事实:

  • Untyped collections (where items are of the type Object ) can store all sorts of values in it. 未类型化的集合(项目属于Object类型)可以在其中存储各种值。

  • Typed collections (where items are of a more specific type, eg T ) can only store values having type T or a type derived from T . 类型化的集合(项具有更特定的类型,例如T )只能存储类型T或从T派生的类型的值。


Third, conclusions drawn from the above: 第三, 从以上得出的结论:

  • In your case, Collection must be an untyped collection, if it is indeed true that poco (having type MyType ) has fields of varying types. 在您的情况下,如果poco (类型为MyType )具有不同类型的字段,则Collection必须为无类型的集合。

  • Generics won't actually help you at all in this case, because that's not what generics are for. 在这种情况下,泛型实际上并不能为您提供任何帮助,因为这不是泛型的用途。 Generics are useful when you want to define operations (ie. methods, behaviour) that work in the same way no matter what type of object they're working on. 当您想要定义以相同方式工作的操作 (即方法,行为)时,无论它们正在处理哪种类型的对象,泛型都是有用的。

    For example, List(Of T) defines a collection type that works the same no matter what type T is. 例如, List(Of T)定义一个不管T是什么类型都起作用的集合类型。 But that does not mean that you can put anything in a List(Of T) , because as soon as you instantiate this type — eg with Dim xs As New List(Of String) —, T will be fixed to a specific type — String —, and you end up with a typed collection that only accepts this type of values. 但这并不意味着您可以将任何内容放入List(Of T) ,因为一旦实例化此类型(例如,使用Dim xs As New List(Of String)T将被固定为特定类型String —,最后得到一个仅接受这种类型的值的类型化集合。

    So, again: If you need a collection that stores different kinds of objects, choose Object as the value type instead of trying to find a solution involving generics. 因此,再次:如果您需要一个存储不同类型对象的集合,请选择Object作为值类型,而不是尝试查找涉及泛型的解决方案。


That being said, there is another solution: polymorphism . 话虽这么说,还有另一个解决方案:多态

If you want your code to handle values differently, depending on their type, polymorphism is the way to go: 如果您希望代码根据值的类型以不同的方式处理值,则多态性是可行的方法:

  • First, you define an interface or an abstract base class (eg DataType , though I'd strongly suggest you choose a more self-explanatory name!) that specifies what can be done with your values. 首先,您定义一个接口或一个抽象基类(例如DataType ,尽管我强烈建议您选择一个更不言自明的名称!)来指定可以用您的值进行的操作。

  • Second, type Collection as Dictionary(Of String, DataType) . 其次,将Collection键入为Dictionary(Of String, DataType) This means that only objects of type DataType or anything derived from it can go into the collection. 这意味着,只有DataType对象或从其派生的任何对象都可以进入集合。

  • Third, derive from/implement DataType to specify behaviour for a particular type. 第三,派生自/实现DataType以指定特定类型的行为。

There is a nice slide show called Conditionals and Polymorphism that may be of interest here. 这里有一个很好的幻灯片,名为“ 条件和多态” ,可能对此感兴趣。


Side note: Last but not least, you can find out the type of a generic type parameter: TypeOf(T) . 旁注:最后但并非最不重要的一点是,您可以找到通用类型参数的类型: TypeOf(T)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM