Antonio "tdj"

(C'è sempre un modo migliore)
posts - 312, comments - 268, trackbacks - 17

My Links

News





Tag Cloud

Article Categories

Archives

Post Categories

Image Galleries

Articoli

Blogs

Controlli WinForm free

Guide

Siti vari

Sviluppo

ChangeType e Nullable

Qualche giorno fà un collega si è trovato di fronte ad una bella eccezione InvalidCastException nel chiamare il metodo ChangeType() della classe Convert su un tipo Nullable (Boolean nello specifico).

Il motivo è che il metodo ChangeType() non supporta il tipo Nullable come target Type. Una rapida ricerca in rete ha confermato che in .NET 2.0 esiste questo problema. Ho voluto verificare se nel FX 3.5 (o meglio, se con il SP1 del FX2.0) le cose fossero cambiate ed invece è rimasto tutto come prima. La conferma l'ho avuta provando il debug del file convert.cs contenente la classe Convert utilizzando la nuova funzionalità di Visual Studio 2008 per il debug delle classi del framework :)

Le soluzioni al problema sono diverse:

  1. Si tratta di un metodo wrapper al ChangeType e lo trovate qui: "Convert.ChangeType Wrapper that Handles Nullable Types".
    Sostanzialmente viene recuperato il tipo del Nullable (UndelingType) e poi chiamato Convert.ChangeType();
  2. Una versione basata sui generics della soluzione al punto 1):

       1:  Public Function ChangeType(Of T, TTarget)(ByVal value As T) As TTarget
       2:      Dim targetType As Type = GetType(T)
       3:   
       4:      If targetType.IsGenericType OrElse _
       5:         targetType.GetGenericTypeDefinition.Equals(GetType(Nullable)) Then
       6:         If value Is Nothing Then Return Nothing
       7:         targetType = Nullable.GetUnderlyingType(targetType)
       8:      End If
       9:      Return CType(Convert.ChangeType(value, targetType), TTarget)
      10:  End Function

    utilizzabile così:

       1:  Dim value As Boolean = False
       2:  Dim s = ChangeType(Of Boolean, String)(value)

  3. Usare il TypeConverter invocando il metodo ConvertFrom:

       1:  Dim tc As TypeConverter = TypeDescriptor.GetConverter(GetType(DateTime?))
       2:  Dim v As DateTime? = CType(tc.ConvertFrom(myValue), DateTime?)

    che può diventare anche un metodo Extension:

       1:   _
       2:  Public Function ChangeType(Of T, TTarget)(ByVal value As T) As TTarget
       3:     Dim tc As TypeConverter = TypeDescriptor.GetConverter(GetType(TTarget))
       4:     Return CType(tc.ConvertFrom(value), TTarget)
       5:  End Function

    utilizzabile in questo modo:

       1:  Dim value As Boolean = False
       2:  Dim s As String = value.ChangeType(Of String)()

Print | posted on domenica 15 marzo 2009 21:30 | Filed Under [ Dev .NET ]

Feedback

Gravatar

# re: ChangeType e Nullable

Alla faccia di chi dice che debuggare il Framework è perfettamente inutile!
Bravo Antonio, veramente un ottimo post, soprattutto nel suggerire una soluzione .NET 3.5-oriented.

Alessandro
27/01/2008 03:59 | Alessandro Del Sole
Gravatar

# re: ChangeType e Nullable

Ero io a dire che debuggare il Framework è perfettamente inutile, e lo confermo... :)
Io trovo quantomeno un qualcosa di non lineare il voler convertire un tipo in nullable...
Mi farei più una domanda del tipo "sto seguendo la logica giusta?" piuttosto che "Perché non si può convertire un tipo in nullable?".
Se poi è il tempo che manca per ristrutturare un po' le cose allora ben vengano le estensioni al metodo che in futuro ci permetteranno di farlo o i wrapper che si possono trovare in giro per la rete... ma ripeto: che vantaggio mi porta in questo scenario vedere il codice sorgente quando c'è già lì una bella eccezione che mi dice cosa sta succedendo?

Senza polemica, saluti
29/01/2008 10:52 | Black MasterX
Gravatar

# re: ChangeType e Nullable

<<<<
Ero io a dire che debuggare il Framework è perfettamente inutile, e lo confermo... :)
>>>>
Personalmente preferisco che il debug del FX lo facciano i programmatori MS :)

<<<<
Io trovo quantomeno un qualcosa di non lineare il voler convertire un tipo in nullable...
>>>>
Certo, se stessi convertendo un tipo Form in Nullable allora avresti sicuramente ragione :)

>>>>
Mi farei più una domanda del tipo "sto seguendo la logica giusta?" piuttosto che "Perché non si può convertire un tipo in nullable?".
>>>>
Una precisazione. Nel mio caso specifico si trattava di convertire un tipo generico Object (contenente sempre un tipo primitivo ValueType)
in un tipo valore (compreso il Nullable).

Il Nullable<T> è sempre un tipo valore di tipo T ma con il supporto per il null. Quindi un int? è sempre un int ed infatti è lecito fare:

Dim x As Integer? = CType("10", Integer?)

che è una conversione a tutti gli effetti, mentre ottieni una eccezione se fai:

Dim o As Object = "10"
Dim x As Integer? = CType(o, Integer?)

Da qui la necessità di utilizzare un sistema diverso e "generico" per gestire tutti i tipi primitivi a partire da un Object.

Il ChangeType mi sembrava perfetto se non fosse stato per l'eccezione di InvalidCast che mi ha lasciato un'attimo perplesso.
Una rapida occhiata all'implementazione del metodo mi ha dato la risposta: questo caso non viene gestito. Stop.

<<<<
che vantaggio mi porta in questo scenario vedere il codice sorgente quando c'è già lì una bella eccezione che mi dice cosa sta succedendo?
>>>>
Semplicemente che non te l'aspetti :)
Ma a prescindere da questo, "sbirciare" il codice del FX ti aiuta a capire molti meccanismi che ci sono dietro, ad esempio, la creazione di un controllo, di una pagina asp.net ecc... rendendoti un programmatore migliore :)
30/01/2008 00:22 | Antonio "tdj" Catucci
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET