TypeDescriptor.GetConverter() 不返回我的转换器

12

我有一个带有自定义类型转换器的简单类型,它在运行时编译和加载。但是TypeDescriptor.GetConverter()找不到正确的转换器。这里是一个独立的示例:

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.CodeDom.Compiler;
using Microsoft.CSharp;

public class Program
{
    private static string src =
@"
using System;
using System.ComponentModel;
namespace LoadMe
{
    [TypeConverter(typeof(FooConverter))]
    public class Foo
    {
    }
    public class FooConverter : TypeConverter
    {
        // stuff
    }
}
";
    public static void Main()
    {
        var codeProvider        = new CSharpCodeProvider(new     Dictionary<string, string>{{ "CompilerVersion", "v4.0" }});
        var compileParameters   = new CompilerParameters(new[] { "System.dll"     }) { GenerateInMemory = true };
        var compilerResults     = codeProvider.CompileAssemblyFromSource(compileParameters, src);

        if (compilerResults.Errors.Count == 0)
        {
            var fooType = compilerResults.CompiledAssembly.GetType("LoadMe.Foo");
            Console.WriteLine(fooType.FullName + "::" + fooType.Assembly.FullName);
            Console.WriteLine("Type converter type = '" + TypeDescriptor.GetConverter(fooType).GetType().FullName + "'");
        }
        else 
        {
            foreach (var err in compilerResults.Errors)
                Console.WriteLine(err);
        }
    }
}

以下是示例的输出(在vs中编译):

LoadMe.Foo::q5sszdls, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Type converter type = 'System.ComponentModel.TypeConverter'

我应该只是挖出属性并自己创建实例,还是我漏掉了其他地方?

同时很奇怪!在LINQPad中作为'C#程序'运行时,它实际上是有效的!这里是输出。 LINQPad准备源

LoadMe.Foo::oqmid5in, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Type converter type = 'LoadMe.FooConverter'

你有什么想法,LINQPad到底是用了什么方法才找到了正确的转换器?


它应该像这样工作,并且一个快速的在线测试显示它确实如此。您能否发布一个最小完整程序,以演示您所描述的行为? - user743382
嗯,类型是在运行时编译的,所以这一定是原因。我会创建一个隔离的示例。 - user2201501
我刚刚将其编辑为独立示例,忘记了编辑注释 :O - user2201501
请查看这里的解决方案:https://dev59.com/2HA65IYBdhLWcg3w1SNC#7052397 - 我们使用它并通过连接另一个AssemblyResolver很好地工作。 - Marwie
1个回答

15

.NET使用反射来加载指定的类型转换器。当您将Type实例传递给TypeConverterAttribute时,您的TypeConverterAttribute将包含一个程序集限定的类型名称。加载该程序集限定的类型名称不起作用,因为找不到该程序集。(是的,即使该程序集已经加载。)

您可以使用接受字符串参数的构造函数重载来指定类型名称,而不需要引用定义程序集,这样它将在与您请求其转换器的类型相同的程序集中查找:

[TypeConverter("LoadMe.FooConverter")]
public class Foo
{
}

5
注意:您也可以在运行时使用TypeDescriptor.AddAttributes添加类型转换器。如果您无法修改该类型,例如因为它是一个.NET框架类型,则这非常有用。 - Ananke
我真是个傻瓜,我已经在属性网格编辑器的其他地方使用了这个概念,但它完全逃过了我的注意。 - user2201501
这个答案非常有帮助。供参考,我必须使用完全限定的命名空间来代替“LoadMe”才能使它工作。 - StayOnTarget
@DaveInCaz 是的。LoadMe是OP使用的完全限定命名空间。 - user743382

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接