Iniettare la conversione del tipo personalizzato in classi di librerie .NET
Domanda
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 [].
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 vorrei che fosse chiamato quando Guid viene convertito in byte []. Il motivo alla base di ciò è 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 TypeConverter, ma non sembra funzionare neanche:
Guid g = new Guid();
TypeConverter tc = TypeDescriptor.GetConverter(typeof(Guid));
byte[] b2 = (byte[])tc.ConvertTo(g, typeof(byte[])); // throws exception
La variabile tc viene impostata su System.ComponentModel.GuidConverter che non supporta le conversioni in byte []. Posso avere due TypeConverter per la stessa classe? Anche se potessi, non dovrei anteporre un attributo al codice sorgente della classe per assegnare un TypeConverter?
Grazie
Soluzione
Puoi cambiare il TypeConverter
registrato per qualcosa usando TypeDescriptor.AddAttributes
; questo non è esattamente lo stesso di 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);
}
}
Altri suggerimenti
System.ComponentModel.ICustomTypeDescriptor
Sì, è possibile. Leggi la documentazione su MSDN per informazioni correlate per "iniettare" quella nel programma in esecuzione. (TypeDescriptor fornisce il metodo IIRC).
Se il codice che esegue la conversione supporta TypeConverter
è possibile utilizzare TypeConverterAttribute
a livello di assembly.
Purtroppo no, non puoi - potresti scrivere un metodo di estensione che apparire sia una conversione tra due tipi come parte del framework.