【问题标题】:Why is this TypeConverter not working?为什么这个 TypeConverter 不起作用?
【发布时间】:2011-04-06 11:44:04
【问题描述】:

我试图理解为什么下面的代码没有按预期工作; 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; }
    }
}

【问题讨论】:

    标签: c# typeconverter


    【解决方案1】:

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

    【讨论】:

    • 我忍不住引用埃尔顿约翰的话:“今晚有人救了我的命……”;-)
    【解决方案2】:

    The answer to this other question 应该适用于此。这是一个比订阅AssemblyResolve 更简单的解决方案。

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

    换句话说,不要这样做:

    [TypeConverterAttribute(typeof(TestConverter))]
    public struct Test
    {
        ...
    }
    

    这样做:

    [TypeConverterAttribute("MyTest.TestConverter")]
    public struct Test
    {
        ...
    }
    

    【讨论】:

    • 试过这个。没用 :( 但话又说回来,无论有没有 typeof,AssemblyResolve 也没有。
    • 事实上,我可以使用 TypeDescriptor.AddAttributes 添加 TypeConverter,并使用 TypeDescriptor.GetConverter 按类型或对象正确检索它,但它仍然没有被 DataBinding 使用。
    • @RogerWillcocks 是您的转换器在另一个组件中吗?也许它没有被使用该属性的人引用?
    • 终于想通了。它是数据绑定。除非“formattingEnabled”为真,否则显然不会调用 TypeConverters。 @UuDdLrLrSs
    • 这对我有用。当类型转换器在数据网格视图中工作但不在复选框列表中时,我遇到了一个奇怪的情况。然后我从 [TypeConverter(typeof(EnumDescriptionConverter))] 更改为 [TypeConverter("my_namespace.EnumDescriptionConverter")] ,然后它在任何地方都有效。转换后的代码是在另一个程序集中定义的,而不是使用它的代码。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 我认为这很可能与它位于不同的组件中有关 - 我刚刚尝试过移动位;当我有一个 PropertyGrid 引用另一个程序集中的项目时,它不能再使用它的 TypeConverters 等来显示该属性。如果没有解决方案,我会感到惊讶。
      【解决方案5】:

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

      万恶之源是TypeDescriptorAttribute 实现中的一个缺陷。

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

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

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

      【讨论】:

      • 确保从该 DLL 到具有该类型的 DLL 的 DLL 引用 - 在您编译它之后,而不仅仅是在项目中。或者使用使用 Roslyn 的新编译器版本进行编译,它不会像原来的那样隐藏 DLL 引用。
      【解决方案6】:

      好的。花了将近一整天的时间来解决 Nullable 类型转换的问题。

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-10
        • 1970-01-01
        • 2014-01-01
        • 2013-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多