我正在用C#开发一个库,该库使用System.Reflection.Emit.TypeBuilder类生成运行时类型,并且我想生成以下类层次结构:

[XmlInclude(typeof(Derived))]
public class Base
{
}

public class Derived : Base
{
}

我通过以下方式使用TypeBuilder类:
class Program
{
    public static void Main(string[] args)
    {
        var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);

        var moduleBuilder = assembly.DefineDynamicModule("Test");

        var baseTypeBuilder = moduleBuilder.DefineType("Base", TypeAttributes.Public, typeof(Object));

        var derivedTypeBuilder = moduleBuilder.DefineType("Derived", TypeAttributes.Public);

        derivedTypeBuilder.SetParent(baseTypeBuilder);

        baseTypeBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(XmlIncludeAttribute).GetConstructor(new[] { typeof(Type) }), new[] { derivedTypeBuilder }));

        var baseType = baseTypeBuilder.CreateType();

        var derivedType = derivedTypeBuilder.CreateType();

        var attribute = baseType.GetCustomAttribute<XmlIncludeAttribute>();
    }
}

电话:
var attribute = baseType.GetCustomAttribute<XmlIncludeAttribute>();

我收到以下错误:

无法加载文件或程序集“测试,版本= 0.0.0.0,区域性=中性,公共(public) key token =空”或其依赖项之一。该系统找不到指定的文件。

任何想法都很容易理解:我如何在TypeBuilder的基类上应用自定义属性,该基类引用派生类的TypeBuilder?

P.S:我正在使用Visual Studio 2017(v15.7.5)和C#类库(.NET Framework项目模板)不是.NET Core或.NET Standard

最佳答案

不能提供太多理由,但是可以提供一种无需额外的加载/卸载或磁盘上的任何操作即可解决的解决方案:

添加一个包含实际Assembly的单独字段,您可以只订阅AppDomain.CurrentDomain.AssemblyResolve并检查是否请求了动态程序集。

如果是这样,您只需要返回您的字段即可,并且效果很好。

例子:

class Program
{
    static Assembly ass;
    public static void Main(string[] args)
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
        var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.Run);

        var moduleBuilder = assembly.DefineDynamicModule("Test");

        var baseTypeBuilder = moduleBuilder.DefineType("Base", TypeAttributes.Public, typeof(Object));

        var derivedTypeBuilder = moduleBuilder.DefineType("Derived", TypeAttributes.Public);

        derivedTypeBuilder.SetParent(baseTypeBuilder);

        baseTypeBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(XmlIncludeAttribute).GetConstructor(new[] { typeof(Type) }), new[] { derivedTypeBuilder }));

        var baseType = baseTypeBuilder.CreateType();

        var derivedType = derivedTypeBuilder.CreateType();
        ass = baseType.Assembly;

        var attribute = baseType.GetCustomAttribute<XmlIncludeAttribute>();

        Console.WriteLine(attribute.Type.FullName);
    }

    private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        return ass;
    }
}

09-11 17:47