为什么这个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; } } } 

我也有这个问题,问题的解决方法是订阅当前应用程序域的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; } 

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

我唯一能做的就是在复杂的场景中,你可能没有reflection权限。

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

这个问题的答案应该适用于此。 这是一个比订阅AssemblyResolve简单得多的解决方案。

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

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

所有邪恶的根源都是TypeDescriptorAttribute实现中的缺陷。

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

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

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