Mam następujący Funkcja (try-catch usunięte):Przełęcz rodzajowo obiekt wpisany do ograniczonej metody rodzajowe VB.NET
Friend Shared Function ConvertOrDefault(Of T As {Structure, IConvertible})(convertFrom As Object, ignoreCase As Boolean) As T
Dim retVal As T
If Not GetType(T).IsEnum Then
Throw New ArgumentException("Type must be enum")
ElseIf convertFrom Is Nothing OrElse Not TypeOf convertFrom Is String Then
Return New T
ElseIf [Enum].TryParse(convertFrom.ToString(), ignoreCase, retVal) Then
Return retVal
Else
Return New T
End If
End Function
który przekształca dany typ do wyliczenia (stąd ograniczenia), jeśli to jest jeden.
To dobrze, ale potem mają inną metodę (uproszczony poniżej), który wykonuje bardziej ogólny casting, i chcę go użyć tej metody, jeśli typ przekazywane w to enum:
Friend Shared Function Convert(Of T)(value as Object) As T
If GetType(T).IsEnum Then
Return Enums.ConvertOrDefault(Of T)(value, True)
Else : return DirectCast(value, T)
End If
End Function
Na wezwanie do Enums.ConvertOrDefault, daje błędy:
Type argument 'T' does not inherit from or implement the constraint type 'System.IConvertible' Type argument 'T' does not satisfy the 'Structure' constraint for type parameter 'T'
Jak mogę powiedzieć „to jest OK, wiem, że to wyliczenia tak jest w porządku”?
--- Edit ---
One (bardzo brzydki) sposób zrobić to w następujący sposób:
Dim type As Type = GetType(T)
If type.IsEnum Then
Select Case type.Name
Case "EnumTypeOne"
Return DirectCast(DirectCast(Enums.ConvertOrDefault(Of EnumTypeOne)(value, True), Object), T)
' ...
Ale to ohydne. Z pewnością istnieje sposób, aby to uogólnić?
- Edycja 2: Cel -
Czytam dane z bazy danych Oracle, który przechowuje przycisk (z czego mam ich kilka) Enums
jako ciągi; a także przechowywanie innych danych w różnych formatach (Byte()
jako RAW
, TimeSpan
jako IntervalDS
itp.). Następnie używam funkcji Convert
jako funkcji ogólnej, gdzie, biorąc pod uwagę wynik datareader(column)
, mogę przekonwertować ten obiekt na odpowiedni typ.
Wszystkie funkcje Oracle.DataAccess.Client.OracleDataReader
pobierają indeks, a nie nazwę kolumny; a ponieważ nie mogę zagwarantować kolejności kolumn, i dla zachowania czytelności, użycie nazwy kolumny ma więcej sensu - ale muszę samemu przeanalizować wynik.
Więc mój kod robi coś takiego:
Dim id as Byte() = Convert(dataReader("id_column"))
Dim something as SomeEnum = Convert(dataReader("somethingCol"))
'...
mogę świadomie zadzwonić Enum.ConvertOrDefault
zamiast Convert
kiedy jestem oczekując Enum
, ale to wydaje się złamać zasadę ogólną metodę, która myślę ma więcej sensu ... i pozwoliłaby mi również na ponowne wykorzystanie tej metody w innych kontekstach.
Nadzieję, że pomaga trochę wyjaśnić.
--- Edycja 3 ---
Próbowałem ten pomysł, z komentarzami:
Friend Shared Function Convert(Of T As {New})(value as Object) as T
i
Friend Shared Function ConvertOrDefault(Of T As{New}) convertFrom As Object, ignoreCase As Boolean) As T
If Not GetType(T).IsEnum Then
Throw New ArgumentException("Type must be enum")
ElseIf convertFrom Is Nothing OrElse Not TypeOf convertFrom Is String Then
Return New T
End If
Try
Return CType([Enum].Parse(GetType(T), convertFrom.ToString(), ignoreCase), T)
Catch ex As Exception
End Try
' default
Return New T
End Function
Ale to daje błędy podczas nazywam Convert
metoda dla typów takich jak String lub Byte(), mówiąc:
„Typ argumentu«String»musi mieć publiczny instancję bez parametrów konstruktora, aby zaspokoić«nowych»ograniczenie dla parametru typu«T»
Trochę niechlujnie byłoby dodać 'Enum' do ograniczeń, ale potem wymusić błąd w instancji. To robi coś bardzo podobnego do niepowodzenia ograniczeń. – Paul
Nie jestem pewien, czy rozumiem, przepraszam. Dodać 'Enum' gdzie? – simonalexander2005
Po prostu mnie zignoruj - zapomniałem, że nie możesz dodać Enuma do ograniczeń ...: -/ – Paul