Ho la seguente funzione (try catch rimosso):Passo genericamente tipizzato in vincolato metodo generico 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
che converte il tipo specificato un'enumerazione (quindi i vincoli), se è uno.
va bene, ma poi ho un altro metodo (semplificato sotto) che fa di fusione più generale, e lo voglio utilizzare questo metodo se il tipo passato è un 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
Per la chiamata a Enums.ConvertOrDefault, questo dà gli errori:
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'
Come faccio a dire "va bene, so che è un Enum quindi va bene"?
--- --- Modifica
Un modo (molto brutta) per farlo è la seguente:
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)
' ...
Ma questo è orribile. Sicuramente c'è un modo per generalizzare questo?
- Modifica 2: Destinazione d'uso -
sto leggendo i dati da un database Oracle, che memorizza l'Enums
(di cui ho diverse) come stringhe; così come la memorizzazione di altri dati in vari formati (Byte()
come RAW
, TimeSpan
come IntervalDS
, ecc.). Quindi utilizzo la funzione Convert
come una funzione generica in cui, dato il risultato di datareader(column)
, posso convertire quell'oggetto nel tipo appropriato.
Tutte le funzioni .Get...
di Oracle.DataAccess.Client.OracleDataReader
prendono un indice anziché un nome di colonna; e siccome non posso garantire l'ordine delle colonne, e per motivi di leggibilità, usare il nome della colonna ha più senso, ma poi devo analizzare personalmente l'output.
Quindi il mio codice sta facendo qualcosa di simile:
Dim id as Byte() = Convert(dataReader("id_column"))
Dim something as SomeEnum = Convert(dataReader("somethingCol"))
'...
ho potuto deliberatamente chiamare Enum.ConvertOrDefault
invece di Convert
quando mi aspetto una Enum
, ma che sembra rompere il principio di un metodo generale, che credo ha più senso ... e mi permetterebbe anche di riutilizzare quel metodo in altri contesti.
La speranza che aiuta a chiarire un po '.
--- --- Modifica 3
ho provato questa idea, dai commenti:
Friend Shared Function Convert(Of T As {New})(value as Object) as T
e
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
Ma questo dà errori quando chiamo il Metodo Convert
per tipi come String o Byte(), dicendo
"Tipo di argomento 'String' deve avere un'istanza senza parametri pubblica costruttore per soddisfare il vincolo 'Nuovo' per il parametro di tipo 'T'
Un modo leggermente disordinato sarebbe aggiungere 'Enum' ai vincoli, ma poi forzare un errore nell'istanza. Questo fa qualcosa di molto simile a un fallimento di vincoli. – Paul
Non sono sicuro di aver capito, mi dispiace. Aggiungi 'Enum' dove? – simonalexander2005
Semplicemente ignorami - dimentica che non puoi aggiungere Enum ai vincoli ...: -/ – Paul