将参数传递给VB.Net Generics中的泛型类型New构造函数

时间:2014-06-13 18:23:51

标签: vb.net generics

我正在尝试将一个Type参数传递给一个名为ConvertList的函数,并让该函数创建一些指定类型的实例。因此,如果我传入了Foo类型,该函数将创建Foo类型的新对象,并将创建的对象放入自定义List对象(SLMR_OBjList)。

该函数位于定义的泛型类中:

Public Class BOIS_Collection_Base(Of T)  

该函数将接受除类定义中传递的类型以外的类型。因此,如果我们创建BOIS_Collection_Base(Of MyTypeA)的实例,我们可以调用函数ConvertList(Of MyTypeB)

我希望私有变量_convertedList与类不同。这可能吗?我似乎只能用(Of T)定义它。

这是我到目前为止所做的:

Public Class BOIS_Collection_Base(Of T)  
    Private _convertedList As SLMR_ObjList(Of T) ' I can only seem to define this as (Of T), but want to make sure I can pass in a Type other than the Base(Of T)
    Public Function ConvertedObjList(Of myT)() As SLMR_ObjList(Of T) ' Should this be (Of T) or (Of myT) since I want it to use whatever Type is passed in
        For Each tempVar In Me.ObjList
            Dim newitem As myT = Activator.CreateInstance(GetType(myT), tempVar)
            ' Next line won't compile, says on newitem 'Value of type 'myT' cannot be converted to 'T'
            _convertedList.Add(newitem)
        Next
        _convertedList.Sort_Direction = Me.Sort_Direction
        _convertedList.Sort_Expression_List = Me.Sort_Expression_List
        Return _convertedList
    End Function

以下是我希望能够做到的事情:

Dim mainCollInstance As New BOIS_Collection_Base(Of MyTypeA)
.... 
'Code that populates the BOIS_Collection_Base.ObjList property with an SLMR_ObjList(Of MyTypeA)
....
' Now I want to take that ObjList, and cast all the items in it to MyTypeB
Dim newListObj As SLMR_ObjList(Of MyTypeB) = mainCollInstance.ConvertList(Of MyTypeB)

这可能吗?我错了吗?

回应Plutonix:
如果我在方法中定义_convertedList,就像这样:

Public Function ConvertedObjList(Of myT)() As SLMR_ObjList(Of myT)
    Dim _convertedList = New SLMR_ObjList(Of myT)

我的错误消失了,方法做了我想要的,但_convertedList在对象中不再是持久的。

2 个答案:

答案 0 :(得分:1)

如果要保留列表,那么每次都不能让消费代码为列表传递不同的类型。这并没有多大意义,除非每次调用它,你只希望函数返回包含给定类型对象的持久列表部分。如果是这种情况,那么您只需要声明_convertedList As SLMR_ObjList(Of Object)然后过滤它并根据需要将其转换为正确的类型。

但是,如果我怀疑是这种情况,那么每次调用函数时,使用者总是会请求将它转换为相同的类型,然后该输出类型实际上不是函数调用的属性。相反,它是整个班级的财产。在这种情况下,您应该让您的类采用两个泛型类型参数,如下所示:

Public Class BOIS_Collection_Base(Of T, TOut)
    Private _convertedList As SLMR_ObjList(Of TOut)

    Public Function ConvertedObjList() As SLMR_ObjList(Of TOut)
        For Each tempVar As T In Me.ObjList
            Dim newitem As TOut = DirectCast(Activator.CreateInstance(GetType(TOut), tempVar), TOut)
            ' Next line won't compile, says on newitem 'Value of type 'myT' cannot be converted to 'T'
            _convertedList.Add(newitem)
        Next
        _convertedList.Sort_Direction = Me.Sort_Direction
        _convertedList.Sort_Expression_List = Me.Sort_Expression_List
        Return _convertedList
    End Function
End Class

答案 1 :(得分:0)

基于之前的相关问题以及MyTypeA和MyTypeB从同一个类继承(从未得到答案)的假设,您可能不需要泛型。无论如何,这应该有助于解决问题的一部分。我还没有看到泛型适合的地方,因为继承可以做你想做的事情:

Class MustInherit BiosItem
    Public Property Name As String
    Public Property TypeCode As String 
    ...
    MustOverride Function Foo(args...) As Type

    Overridable Property FooBar As String    
    ' etc - the more stuff in the base class the better

End Class
Class TypeA
    Inherits ABClass

    Public Sub New
       MyBase.New        ' stuff common to all child types
       TypeCode = "A"    ' EZ type ID rather than GetType
       ...
    End Sub
End Class

类TypeB将是相同的,但将TypeCode初始化为“B”。 C-Z也一样。这些允许您轮询对象而不是需要GetType:If thisObj.TypeCode = "A" Then...。现在,集合类:

Public Class BIOSItems
    Inherits Collection(Of BiosItem)
    ' inheriting from Collection<T> provides Add, Count, IndexOf for us
    '    most important the Items collection
    '
End Class

将收藏集标记为BiosItem将允许其中包含TypeATypeJTypeQ。因此,您的收藏集将仅保留一个类型。这是有效的,因为GetType(TypeA)的项目也是GetType(BiosItem)。另见最后的说明。

将一个项目转换为另一个项目似乎主要由正在创建或转换为的新项目处理。由于它们可能非常相似,因此可以通过构造函数重载来处理(如果它们不相似,那么我们就在错误的道路上):

' a ctor overload to create the new thing based on the old things props
Public Sub New(oldThing As BiosItem)
    MyClass.New           ' start with basics like TypeCode, MyBase.New

    With BiosItem         ' coversion
        myFoo = .Foo
        myBar = .Bar       ' copy common prop vals to self
        ...
        Select Case .TypeCode
            Case "B"
                myProp1 = .Prop33     ' conversions
                myProp3 = .Prop16 + 3.14
                ... 
        End Select

        ' then initialize stuff unique to this type maybe
        ' based on other props
        If .PropX = "FooBar" Then myPropZ = "Ziggy"
     End With
End Sub

创建,转换,存储的代码:

Dim varOldBItem As TypeB = myBiosCol(ndx)   ' get old item
Dim varAItem As New TypeA(varOldBItem)      ' call the ctor above
myBiosCol.Add(varAItem)                     ' add new item
myBiosCol.Remove(varoldBItem)               ' delete the old if need be

如果BOIS_Collection_Base总是应该包含MyTypeA,那么就这样输入(继承自Collection<T>仍然按顺序)。如果MyTypeB对象永远不会直接添加到集合中,但是首先转换为MyTypeA(编辑使其不那么清楚),那么除了继承之外,上述大部分仍然适用。 MyTypeA上的ctor重载仍然可以使用旧的B对象并基于它创建自身。如果他们不从同一个基类继承,我不太愿意通过ctor这样做,但它可以完成。