簡體   English   中英

通用函數和操作/返回取決於類型

[英]Generic Function and action/return depending on Type

我有一個函數,它反序列化API發送的一些自定義序列化。 我想構建一個泛型函數,以便反序列化的對象不是Object類型,而是正確的類型。

包含序列化對象的字符串可以反序列化為以下類型之一:

  • 一個String
  • 一個IList(Of String)
  • 一個IDictionnary(Of String)
  • 許多SomeNameContainer類中的一個,都是從BaseContainer類派生的,
  • IList(Of SomeNameContainer) ,或
  • 一個IDictionnary(Of SomeNameContainer)

我想將一個Function Deserialize(Of T)(MyString as String) as T 在這個函數中,我嘗試運行一些Select Case T: GetType(String):Etc測試,以便將不同的動作分開在MyString上運行,具體取決於從反序列化創建的預期對象。

例如,反序列化為SomeNameContainer通常通過另一個泛型函數完成: Dim Deserialized as SomeNameContainer = GetFromContainer(SomeNameContainer)(MyString)

但是,我很快就受到限制,主要是因為:

  1. 我無法返回String類型,因為它無法將其轉換為T.
  2. String是值類型,而SomeNameContainer是類。 因此無法添加(Of T As {New})約束。 這意味着我無法像Dim NameContainer as New T: If TypeOf NameContainer Is BaseContainer ,則將相同的操作應用於從BaseContainer派生的所有類。

我發現的一個軌道是使用CTypeDynamic(Of T)(obj as object) ,它在運行時進行轉換。 這可能會解決問題1,但問題2仍然存在。

Function Deserialize(Of T)(MyString as String) as T

    Select Case GetType(T)

        Case GetType(String)
            Return SomeFunction(String) '<- Only run-time casting allowed: Return CTypeDynamic(Of String)(SomeFunction(String))

        Case GetType(IList(Of String)
            Return SomeOtherFunction(String)

        Case GetType(...)
            '...

        Case Else

            Dim MyContainer as New T '<- Not Allowed to use New

            if TypeOf MyContainer Is T then
                Return GetFromContainer(Of T)(String)
            else
                '...
            End If

    End Select

End Function

我可以決定將每個Type拆分成一個單獨的函數。 我想避免,所以我最終沒有6個功能。 那是因為我還需要在反序列化之前對字符串運行一些其他操作。 對於故事,字符串采用各種編碼/加密格式。 因此,如果我有4種格式,那么現在需要處理的是4x6 = 24種函數。

我很樂意將所有解碼/反序列化封裝到一個函數中: Dim MyObject as Something = Deserialize(Of Something)(StringFromAPI, MyEncodingEnumOptions.Option42)

提前謝謝了!

根據特定變量的類型執行特定操作:感覺類似於重載,除了此處而不是基於輸入變量的類型執行操作,它應該基於輸出變量的類型。

不幸的是,不可能重載泛型函數的TypeName。 例如, Function MyFunction(Of T as New)(SomeParameter as String) as TFunction MyFunction(Of T as Structure)(SomeParameter as String) as T不能在同一名稱空間中共存。

另一種方法是將預期的輸出類型作為輸入參數傳遞,以便可以執行常規重載: Sub MyFunction(ByVal SomeParameter as String, ByRef OutputVar as SomeType) 每個重載包括不同的SomeType TypeName。

“function”的輸出存儲在OutputVar ,它傳遞給ByRef並在運行Sub后檢索:

Dim MyObject as Something = Deserialize(Of Something)(StringFromAPI, MyEncodingEnumOptions.Option42)

Sub Deserialize(ByRef MyObject as String, ByVal MyString As String, ByVal EncodingOption As MyEncodingEnumOptions)
    MyString = SomeDecoding(MyString,  EncodingOption)
    MyObject = SomeFunction(MyString)
End Sub

Sub Deserialize(ByRef MyObject as IList(Of String), ByVal MyString As String, ByVal EncodingOption As MyEncodingEnumOptions)
    MyString = SomeDecoding(MyString, EncodingOption)    
    MyObject = SomeOtherFunction(MyString)
End Sub

'...

Dim MyObject as Something
Deserialize(MyObject, StringFromAPI, MyEncodingEnumOptions.Option42)
'Now MyObject has been filled with the relevant data.

另一種方法是使用Activator.CreateInstance(Of T)使用后期綁定/運行時對象啟動。 典型的T切換看起來像:

Public Function GetDeserializedObject(Of T)(ByVal MyString As String) As T

    Select Case GetType(T)

        Case GetType(String)

            Return CTypeDynamic(MyString, GetType(T)) '<-- Runtime Casting

        Case Else

            If Not MyString.IsDeserializable Then Throw New ArgumentException(String.Format("Unable to deserialize to a {0} object: The provided string is not valid.", GetType(T).ToString))

            Select Case GetType(T)

                Case GetType(IList(Of String))
                    Return CollectionString.ToStringList(MyString)

                Case Else

                    Dim MyReturn As T = Activator.CreateInstance(Of T) '<-- Object instantiation to the type provided at Runtim 

                    If TypeOf MyReturn Is BaseContainer Then '<-- Now we can use TypeOf ... Is ... which will return True for all Object derived from BaseContainer 
                        Return Activator.CreateInstance(GetType(T), MyString)

                    ElseIf TypeOf MyReturn Is IList(Of BaseContainer) Then
                        Dim MyCollectionString As CollectionString = MyString
                        Return MyCollectionString.ExportToContainerList(MyReturn.GetType)

                    Else

                        Throw New ArgumentException(String.Format("Unable to deserialize to a {0} object: This type of object is not supported.", GetType(T).ToString))

                    End If

            End Select

    End Select

End Function

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM