2009-03-03 9 views
21

Vorrei implementare la conversione tra due classi di libreria da Convert.ChangeType in C#. Non posso cambiare nessuno dei due tipi. Ad esempio la conversione tra Guid e byte [].Iniettare la conversione del tipo personalizzato in classi di librerie .NET

Guid g = new Guid(); 
object o1 = g; 
byte[] b = (byte[]) Convert.ChangeType(o1, typeof(byte[])); // throws exception 

Sono consapevole che Guid fornisce un metodo ToByteArray(), ma mi piacerebbe avere quel chiamato quando Guid viene convertito in byte []. La ragione di questo è che la conversione avviene anche nel codice della libreria (AseDataAdapter) che non posso modificare. Quindi è possibile definire una regola di conversione tra due tipi senza modificare il codice sorgente di una delle due classi?

stavo sperimentando con TypeConverter, ma non sembra funzionare sia:

Guid g = new Guid(); 
TypeConverter tc = TypeDescriptor.GetConverter(typeof(Guid)); 
byte[] b2 = (byte[])tc.ConvertTo(g, typeof(byte[])); // throws exception 

TC variabile imposta System.ComponentModel.GuidConverter che non supporta le conversioni al byte []. Posso avere due TypeConverters per la stessa classe? Anche se potessi, non dovrei anteporre un attributo al codice sorgente della classe per assegnare un TypeConverter?

Grazie

risposta

36

È possibile modificare il TypeConverter registrato per qualcosa utilizzando TypeDescriptor.AddAttributes; questo non è del tutto identica a Convert.ChangeType, ma può bastare:

using System; 
using System.ComponentModel; 
static class Program 
{ 
    static void Main() 
    { 
     TypeDescriptor.AddAttributes(typeof(Guid), new TypeConverterAttribute(
      typeof(MyGuidConverter))); 

     Guid guid = Guid.NewGuid(); 
     TypeConverter conv = TypeDescriptor.GetConverter(guid); 
     byte[] data = (byte[])conv.ConvertTo(guid, typeof(byte[])); 
     Guid newGuid = (Guid)conv.ConvertFrom(data); 
    } 
} 

class MyGuidConverter : GuidConverter 
{ 
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
     return sourceType == typeof(byte[]) || base.CanConvertFrom(context, sourceType); 
    } 
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
    { 
     return destinationType == typeof(byte[]) || base.CanConvertTo(context, destinationType); 
    } 
    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) 
    { 
     if (value != null && value is byte[]) 
     { 
      return new Guid((byte[])value); 
     } 
     return base.ConvertFrom(context, culture, value); 
    } 
    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 
    { 
     if (destinationType == typeof(byte[])) 
     { 
      return ((Guid)value).ToByteArray(); 
     } 
     return base.ConvertTo(context, culture, value, destinationType); 
    } 
} 
+1

Grazie per un buon esempio :) – leppie

+0

+1 Non si è nemmeno reso conto che è possibile aggiungere attributi tramite TypeDescriptor.AddAttributes - che potrebbe essere estremamente utile. –

+5

Si noti che non sono attributi * real * - il riflesso non li vedrà; solo System.ComponentModel –

-2

Purtroppo no non è possibile - si potrebbe scrivere un metodo di estensione che sembrerebbe essere una conversione tra due tipi come parte del quadro.

0

Se il codice che esegue la conversione supporta TypeConverter s è possibile utilizzare TypeConverterAttribute a livello di assembly.

+0

AFAIK, non v'è alcun uso a livello di assemblaggio TypeConverterAttribute; puoi eseguire per tipo e per proprietà e eseguire l'override tramite TypeDescriptor, ma non a livello di assembly? Ho perso qualcosa? –

+0

TypeConverterAttribute è dichiarato AttributeTargets.All ... e ISTR vedendo questo usato in WF. – Richard

0
System.ComponentModel.ICustomTypeDescriptor 

Sì, è possibile. Leggere la documentazione su MSDN per informazioni correlate a 'iniettare' nel programma in esecuzione. (TypeDescriptor fornisce il metodo IIRC).

+0

Ciò è massicciamente eccessivo ... utilizzare [TypeConverter] su una singola proprietà (rispettata da PropertyDescriptor) o utilizzare l'approccio globale mostrato nel mio post. –

Problemi correlati