【问题标题】:Inject custom type conversion to .NET library classes将自定义类型转换注入 .NET 库类
【发布时间】:2010-10-11 01:09:23
【问题描述】:

我想通过 C# 中的 Convert.ChangeType 来实现两个库类之间的转换。我不能改变这两种类型。例如 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 吗?

谢谢

【问题讨论】:

    标签: c# .net guid


    【解决方案1】:

    您可以使用TypeDescriptor.AddAttributes 更改注册的TypeConverter;这与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);
        }
    }
    

    【讨论】:

    • +1 甚至没有意识到您可以通过 TypeDescriptor.AddAttributes 添加属性 - 这可能非常有用。
    • 请注意,它们不是 真正的 属性 - 反射不会看到它们;只有 System.ComponentModel
    • Marc,您能否详细说明使用自定义TypeDescriptorProvider 并重载GetTypeDescriptor->GetConverter 链?它似乎产生了相同的结果,并且使用TypeDescriptor.AddProvider 实际注册时稍微干净一些,尽管它当然更冗长,因为您需要同时创建TypeDescriptorProviderICustomTypeDescriptor。以这种方式注册它会完全覆盖该对象的标准TypeDescriptor,还是与现有注册组合在一起?
    【解决方案2】:

    如果执行转换的代码支持TypeConverters,您可以在程序集级别使用TypeConverterAttribute

    【讨论】:

    • AFAIK,TypeConverterAttribute 没有汇编级用法;你可以做每个类型和每个属性,并通过 TypeDescriptor 覆盖 - 但没有装配级别?我错过了什么吗?
    • TypeConverterAttribute 被声明为 AttributeTargets.All... 并且 ISTR 看到它在 WF 中使用。
    【解决方案3】:
    System.ComponentModel.ICustomTypeDescriptor
    

    是的,这是可能的。阅读 MSDN 上的文档以获取将其“注入”到正在运行的程序中的相关信息。 (TypeDescriptor 提供方法 IIRC)。

    【讨论】:

    • 这太过分了...要么在单个属性上使用 [TypeConverter](受 PropertyDescriptor 尊重),要么使用我的帖子中显示的全局方法。
    【解决方案4】:

    很遗憾,你不能——你可以编写一个扩展方法,看起来是作为框架的一部分的两种类型之间的转换。

    【讨论】:

      猜你喜欢
      • 2011-08-17
      • 2022-01-22
      • 2021-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-16
      • 1970-01-01
      • 2015-10-27
      相关资源
      最近更新 更多