为什么这个TypeConverter不工作?

时间:2010-08-31 20:22:16

标签: c# typeconverter

我试图理解为什么下面的代码没有按预期工作; TypeDescriptor根本就没有从属性中获取自定义转换器。我只能假设我犯了一个明显的错误,但我看不到它。

- 编辑 - 这个代码似乎在我自己在控制台中运行时起作用,我实际上是从一个更复杂的应用程序和一个不同的命名空间中调用转换器。

- 编辑 - 或者有关如何调试TypeDescriptor的任何建议,以便我可以看到发生了什么,然后我可以自己回答。

- 编辑 - 这个问题几乎肯定与不同组件中的碎片有关。

- 编辑 - 由于动态加载程序集的一些怪癖似乎无法正常工作 - 此代码在类似架构的插件下运行。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.ComponentModel;

namespace MyTest
{

    public class TestTester
    {
        public static void Main(string[] args)
        {
            object v = TypeDescriptor.GetConverter(typeof(MyTest.Test)).ConvertFromInvariantString("Test");
        }
    }

    public class TestConverter : TypeConverter
    {

        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return false;
        }

        public override bool CanConvertFrom(ITypeDescriptorContext context, System.Type sourceType)
        {
            if (sourceType == typeof(string) || base.CanConvertFrom(context, sourceType))
            {
                return true;
            }
            return base.CanConvertFrom(context, sourceType);
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(Test) || base.CanConvertTo(destinationType))
            {
                return true;
            }
            return base.CanConvertTo(context, destinationType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value.GetType() == typeof(string))
            {
                Test t = new Test();
                t.TestMember = value as string;
                return t;
            }
            return base.ConvertFrom(context, culture, value);
        }

        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string) && value.GetType() == typeof(Test))
            {
                return ((Test)value).TestMember;
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }

    }

    [TypeConverterAttribute(typeof(TestConverter))]
    public struct Test
    {
        public string TestMember { get; set; }
    }
}

6 个答案:

答案 0 :(得分:12)

我也有这个问题,问题的解决方法是订阅当前应用程序域的AssemblyResolve事件并手动解析程序集。

这远不是一个好的解决方案,但似乎有效。我不知道为什么框架会以这种方式运行。我本人真的想找到一种解决这个问题的不那么强硬的方式。

public void DoMagic()
{
    // NOTE: After this, you can use your typeconverter.
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    AppDomain domain = (AppDomain)sender;
    foreach (Assembly asm in domain.GetAssemblies())
    {
        if (asm.FullName == args.Name)
        {
            return asm;
        }
    }
    return null;
}

答案 1 :(得分:2)

The answer to this other question应适用于此处。这比订阅AssemblyResolve要简单得多。

总之,我们的想法是使用类型转换器类的完整字符串名称设置TypeConverter属性,而不是使用typeof来提供类名。

答案 2 :(得分:1)

我见过一些案例,我无法从其他程序集中获取内部字段的属性。不确定它是否是.NET错误或是否已修复。

我能做的唯一事情就是在复杂的情况下,你可能没有反射许可。

答案 3 :(得分:1)

这有点晚了,但是当我要求一个TypeConverter驻留在另一个程序集中时,就出现了这个问题,而这个程序集并没有被可执行程序集直接引用。

答案 4 :(得分:0)

我们还在可插拔系统中发现了这种行为,涉及从appbase文件夹外部加载程序集。

邪恶的根源是TypeDescriptorAttribute实施中的一个缺陷。

该属性有两个构造函数重载,一个用于明文类型规范(不是出乎意料的是 - 运行时的纯魔术),另一个用于早期绑定typeof()引用。如果您使用第二条路径,可能会出现什么问题?实际上,该属性仅使用第一个路径。真实和正确的运行时类型引用被展平为明文,这里有龙。所以写typeof()是没有用的 - 它总是里面的明文和魔法场景。

解决方案?不理想,但在我们的情况下,我们只在系统中使用类型转换,因此我们选择了ValueSerializerAttribute。这基本上是WPF做同样事情的方式。它的实现在typeof() .ctor重载周围是正确的,因为它成功地保留了早期绑定的类型标识,并且总是加载正确的类型,如代码所示。

如果您希望系统(或WinForms)代码使用类型转换器,这将无济于事。

答案 5 :(得分:0)

好。整整花了整整一天的时间试图找出可空类型转换。

txt.DataBindings.Add(nameof(txt.Text), this.Setting, propertyName);  //fails
txt.DataBindings.Add(nameof(txt.Text), this.Setting, propertyName, false, DataSourceUpdateMode.OnValidation, null, format); //fails
txt.DataBindings.Add(nameof(txt.Text), this.Setting, propertyName, **true**, DataSourceUpdateMode.OnValidation, null, format); //WORKS