2009-03-03 17 views
21

Me gustaría implementar la conversión entre dos clases de biblioteca mediante Convert.ChangeType en C#. No puedo cambiar ninguno de los dos tipos. Por ejemplo, convirtiendo entre Guid y byte [].Inyectar conversión de tipo personalizado a clases de biblioteca .NET

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

Soy consciente de que Guid proporciona un método ToByteArray(), pero me gustaría tener que llama cuando se convierte en Guid byte []. La razón detrás de esto es que la conversión también tiene lugar en el código de la biblioteca (AseDataAdapter) que no puedo modificar. Entonces, ¿es posible definir una regla de conversión entre dos tipos sin modificar el código fuente de ninguna de las dos clases?

Estaba experimentando con TypeConverter, pero no parece funcionar bien:

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

El TC variables se establece en System.ComponentModel.GuidConverter que no soporta conversiones a byte []. ¿Puedo tener dos TypeConverters para la misma clase? Incluso si pudiera, ¿no tendría que anteponer un atributo al código fuente de la clase para asignar un TypeConverter?

Gracias

Respuesta

36

Puede cambiar el TypeConverter registrado por algo usando TypeDescriptor.AddAttributes; esto no es exactamente lo mismo que Convert.ChangeType, pero puede ser suficiente:

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

Gracias por un buen ejemplo :) – leppie

+0

+1 Ni siquiera se dio cuenta de que podría agregar atributos a través de TypeDescriptor.AddAttributes, que podría ser extremadamente útil. –

+5

Tenga en cuenta que no son atributos * reales *; la reflexión no los verá; solo System.ComponentModel –

-2

Desafortunadamente no, no puedes - se podría escribir un método de extensión que sería parece ser una conversión entre dos tipos como parte del marco.

0

Si el código que realiza la conversión admite TypeConverter s, puede usar TypeConverterAttribute en un nivel de conjunto.

+0

AFAIK, no hay uso de nivel de ensamblado de TypeConverterAttribute; puede hacer por tipo y por propiedad, y anular a través de TypeDescriptor, pero no a nivel de conjunto? ¿Me he perdido algo? –

+0

TypeConverterAttribute se declara AttributeTargets.All ... e ISTR al ver esto utilizado en WF. – Richard

0
System.ComponentModel.ICustomTypeDescriptor 

Sí, es posible. Lea la documentación en MSDN para obtener información relacionada a 'inyectar' eso en el programa en ejecución. (TypeDescriptor proporciona el método IIRC).

+0

Eso es excesivamente masivo ... use [TypeConverter] en una propiedad individual (respetado por PropertyDescriptor), o use el enfoque global que se muestra en mi publicación. –

Cuestiones relacionadas