Внедрить преобразование пользовательских типов в классы библиотеки .NET - PullRequest
22 голосов
/ 03 марта 2009

Я хотел бы реализовать преобразование между двумя библиотечными классами с помощью Convert.ChangeType в C #. Я не могу изменить ни один из двух типов. Например, преобразование между Guid и byte [].

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

Мне известно, что Guid предоставляет метод ToByteArray (), но я бы хотел, чтобы он вызывался при преобразовании Guid в byte []. Причина этого заключается в том, что преобразование также происходит в коде библиотеки (AseDataAdapter), который я не могу изменить. Так возможно ли определить правило преобразования между двумя типами без изменения исходного кода любого из двух классов?

Я экспериментировал с TypeConverter, но, похоже, тоже не работает:

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

Переменная tc устанавливается в System.ComponentModel.GuidConverter, которая не поддерживает преобразования в byte []. Могу ли я иметь два TypeConverter для одного класса? Даже если бы я мог, не нужно ли мне добавлять атрибут к исходному коду класса для назначения TypeConverter?

Спасибо

Ответы [ 4 ]

44 голосов
/ 03 марта 2009

Вы можете изменить зарегистрированный TypeConverter для чего-либо, используя TypeDescriptor.AddAttributes; это не совсем то же самое, что Convert.ChangeType, но может быть достаточно:

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);
    }
}
0 голосов
/ 03 марта 2009

Если код, выполняющий преобразование, поддерживает TypeConverter s, вы можете использовать TypeConverterAttribute на уровне сборки.

0 голосов
/ 03 марта 2009
System.ComponentModel.ICustomTypeDescriptor

Да, это возможно. Прочтите документацию по MSDN для получения соответствующей информации, чтобы «внедрить» ее в работающую программу. (TypeDescriptor предоставляет метод IIRC).

0 голосов
/ 03 марта 2009

К сожалению, нет, вы не можете - вы могли бы написать метод расширения, который бы выглядел как преобразование между двумя типами как часть структуры.

...