【问题标题】:Retrieve Type Foo<Bar> from name when Bar is created from TypeBuilder当从 TypeBuilder 创建 Bar 时,从名称中检索类型 Foo<Bar>
【发布时间】:2017-04-06 00:21:30
【问题描述】:

我正在使用TypeBuilder 创建类型。然后将这些类型用作泛型类中的参数。我想做的是根据其名称创建Type。泛型参数是动态的这一事实似乎是一个障碍。

static public class DynamicTypeTest
{
    public class Generic<T> { }

    static public void Test()
    {
        Type dynamicType = createDynamicType();
        Type genericType = typeof(Generic<>);

        // Generic<DynamicType>
        Type genericDynamicType = genericType.MakeGenericType(new Type[]{dynamicType});

        Debug.Assert(TypeFromName(genericDynamicType.FullName) == genericDynamicType);              // fail
        Debug.Assert(TypeFromName(genericDynamicType.AssemblyQualifiedName) == genericDynamicType); // fail
        Debug.Assert(TypeFromName(genericDynamicType.Name) == genericDynamicType);                  // fail

        // Generic<int>
        Type genericIntType = genericType.MakeGenericType(new Type[] { typeof(int) });

        Debug.Assert(TypeFromName(genericIntType.FullName) == genericIntType); // This succeeds. Replacing 'int' with a Type defined in another project also works
    }

    // This is the essence of what I want to do
    static private Type TypeFromName(string name)
    {
        return Assembly.GetExecutingAssembly().GetType(name);
    }

    static private Type createDynamicType()
    {
        AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
        TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass;
        TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicType", typeAttributes, typeof(System.Object));

        return typeBuilder.CreateType();
    }
}

显然我知道如何从 MakeGenericType 创建 Type,但在我正在使用的现实生活场景中,我不想(或不能)修改类型名称,以便我可以分别创建类型并将它们拼凑在一起。

如何从string 名称重新创建这种Type

【问题讨论】:

  • 好吧,您生成的类型存在于您称为DynamicAssembly 的程序集中,对吗?那么为什么要在 executing 程序集中寻找它呢?
  • Generic&lt;&gt; 存在于执行程序集中。还从执行装配工作中检索Generic&lt;int&gt;。 (从 DynamicAssembly 检索 Generic&lt;DynaminType&gt; 不起作用 - 我确实尝试过。)
  • DynamicAssembly 中检索DynamicType 和从ExecutingAssembly 中检索Generic&lt;&gt;(或者如果您静态知道typeof,则仅使用typeof)。然后使用MakeGenericType 将它们放在一起。
  • 我不想检索DynamicType。我正在尝试检索Generic&lt;DynamicType&gt;。看看名为genericDynamicType 的变量。

标签: c# types .net-assembly typebuilder


【解决方案1】:

我想到我应该使用Assembly.GetType() 的版本,它会在错误时引发Exception。它抛出了一个FileNotFoundException,显然,在通用参数中,只允许来自文件的程序集。为了解决这个问题,我从AppDomain注册了AssemblyResolve事件,并处理了DynamicAssembly在文件中找不到的情况。我的工作代码:

static public class DynamicTypeTest
{
    public class Generic<T> { }

    static public void Test()
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

        Type dynamicType = createDynamicType();
        Type genericType = typeof(Generic<>);

        // Generic<DynamicType>
        Type genericDynamicType = genericType.MakeGenericType(new Type[]{dynamicType});

        Debug.Assert(TypeFromName(genericDynamicType.FullName) == genericDynamicType); // pass

        AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
    }

    static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            AssemblyName assemblyName = assembly.GetName();

            if (args.Name == assemblyName.FullName)
            {
                return assembly;
            }
        }

        return null;
    }

    // This is the essence of what I want to do
    static private Type TypeFromName(string name)
    {
        try
        {
            return typeof(Generic<>).Assembly.GetType(name, true);
        }
        catch (Exception)
        {
            return null;
        }
    }

    static private Type createDynamicType()
    {
        AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
        TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.AutoClass | TypeAttributes.AnsiClass;
        TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicType", typeAttributes, typeof(System.Object));

        return typeBuilder.CreateType();
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-30
    • 2022-11-04
    • 2010-12-09
    • 2014-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多