简体   繁体   English

在不知道泛型类型的情况下转换为泛型类型

[英]Cast to a generic type without knowing generic type

I have an interface ( ValueControl ) using a generic type and have another class ( ValueControlHandler ) which uses an instance of that interface.我有一个使用泛型类型的接口( ValueControl ),还有另一个使用该接口实例的类( ValueControlHandler )。 Now when I create ValueControlHandler in CreateHandler I need to pass the generic types.现在,当我在CreateHandler创建ValueControlHandler ,我需要传递泛型类型。 Now TCtrl is "easy" (I just use ValueControl but I don't know how to set TVal .现在TCtrl是“简单的”(我只使用ValueControl但我不知道如何设置TVal

Public Interface ValueControl(Of T)
    ReadOnly Property Value As T
End Interface

Public Interface CtrlChanges
    Function HasChanges() As Boolean
End Interface

Friend Class ValueControlHandler(Of TCtrl As ValueControl(Of TVal), TVal)
    Implements CtrlChanges
    ....
End Class

Private Function DummyCreateHandler(Of TVal)(ByVal ctrl as ValueControl(Of TVal)) As CtrlChanges
    Return New ValueControlHandler(Of ValueControl(Of TVal), TVal)(ctrl)
End Function

Private Function CreateHandler(ByVal ctrl As Object) As CtrlChanges
    If TypeOf ctrl Is ValueControl(Of ValueControl(Of ???), ???) Then  ' <!--- Problem here
        Return New ValueControlHandler(Of ValueControl(Of ???), ???)(ctrl)  ' <!--- Problem here
    ElseIf Typeof ctrl Is AnotherType Then
        Return New AnotherCtrlChanges(....)
    Else
        Return Nothing
    End If
End Function

The tricky part is, that I don't even need to know the type as I'm interested in the CtrlChanges part.棘手的部分是,我什至不需要知道类型,因为我对CtrlChanges部分感兴趣。 Is the only solution to drop the generics and default to Object ?是删除泛型并默认为Object的唯一解决方案吗? I also tried it with DummyCreateHandler but then I still don't know how to check the type and it didn't really help much for the second call.我也用DummyCreateHandler尝试过,但后来我仍然不知道如何检查类型,而且它对第二次调用并没有太大帮助。

Here is the complete class from ValueControlHandler if this helps:如果有帮助,这里是ValueControlHandler的完整类:

Friend Class ValueControlHandler(Of TCtrl As ValueControl(Of TVal), TVal)
    Implements CtrlChanges

    Protected ReadOnly Ctrl As TCtrl

    Protected ReadOnly Val As TVal

    Public Sub New(ByVal Ctrl As TCtrl)
        Me.Ctrl = Ctrl
        Me.Val = CurrentValue
    End Sub

    Public ReadOnly Property CurrentValue As TVal
        Get
            Return Ctrl.Value
        End Get
    End Property

    Public Overridable Function HasChanges() As Boolean Implements CtrlChanges.HasChanges
        Return CType(CurrentValue, Object) <> Val
    End Function
End Class

Have you considered including a factory method as part of ValueControl ?您是否考虑过将工厂方法作为ValueControl一部分? (Side note, the "I" prefix on interfaces is a standard convention) (旁注,接口上的“I”前缀是标准约定)

(Note, my VB.NET is a bit rusty, hopefully you can get the intent of this approach despite my typos): (注意,我的 VB.NET 有点生疏,希望你能理解这种方法的意图,尽管我有错别字):

Public Interface IValueControl(Of T)
   ReadOnly Property Value As T
   ValueControlHandler(Of T) CreateValueControlHandler(ctrl As IValueControl(Of T))
End Interface

Then each control can generate it's own ValueControlHandler :然后每个控件可以生成它自己的ValueControlHandler

Public Class MyControl Inherits Textbox Implements IValueControl(Of String)

   Public Function ValueControlHandler(Of T) CreateValueControlHandler()

      Return New ValueControlHandler(Of MyControl, String)(Me)

   End Fucntion

End Class

CreateHandler could take the type to parameterize on as an argument. CreateHandler可以将要参数化的类型作为参数。 Then, you would do something like this:然后,你会做这样的事情:

Private Function CreateHandler(ByVal ctrl As Object, ByVal TVal as Type) As CtrlChanges

    '...
    Dim genericValueControlType = GetType(ValueControl(Of )) 'Intentionally blank, the type is the unspecialized generic type.
    Dim specificValueControlType = genericValueControlType.MakeGenericType(TVal)

    'Untested, might need to be Is instead of =
    If ctrl.GetType() = specificValueControlType Then
        Dim genericHandlerType = GetType(ValueControlHandler(Of ) 'Untested, might need a comma to indicate two missing type params
        Dim specificHandlerType = genericHandlerType.MakeGenericType(specificValueControlType, TVal)
        Dim retval = specificHandlerType.GetConstructor({}).Invoke({})
        Return CType(retval, CtrlChanges)
    End If
End Function

Depending on the level of detail in your factory routine, you could also consider building up based on reflection and/or one or more conventions.根据工厂例程中的详细程度,您还可以考虑基于反射和/或一种或多种约定进行构建。 Unfortunately, the lack of static interface methods in .NET means that convention is the only way to invoke a logically- Shared routine across different implementations of an interface (that, or making something that is logically Shared a per-instance method anyway so that it can be put on an interface; I've done both and neither is completely satisfactory).不幸的是,.NET 中缺少静态接口方法意味着约定是在接口的不同实现之间调用逻辑Shared例程的唯一方法(即,或者使逻辑上Shared的某些东西成为每个实例的方法,以便它可以放在一个界面上;我两个都做过,但都不完全令人满意)。

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

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