如何将XmlIncludeAttribute应用于TypeBuilder?

Tim*_*nem 12 .net c# reflection reflection.emit

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

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

public class Derived : Base
{
}
Run Code Online (Sandbox Code Playgroud)

我以下列方式使用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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

电话:

var attribute = baseType.GetCustomAttribute<XmlIncludeAttribute>();
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

无法加载文件或程序集'Test,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = null'或其依赖项之一.该系统找不到指定的文件.

任何想法都很受欢迎:如何在TypeBuilder上为引用类引用TypeBuilder的基类应用自定义属性?

PS:我使用的是Visual Studio 2017(v15.7.5)和C#类库(.NET Framework项目模板),而不是.NET Core或.NET Standard

X39*_*X39 7

无法提供太多理由,但解决方案无需额外加载/卸载或任何来自磁盘的工作:

添加一个包含实际的单独字段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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*eev 4

我已经重现了你的异常。.NET Framework 似乎想要从磁盘读取模块。

因此,最简单的解决方法是将程序集保存到磁盘:

var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
  new AssemblyName("Test"), 
  AssemblyBuilderAccess.RunAndSave); // allow run & save

var moduleBuilder = assembly.DefineDynamicModule("Test",
  "Test.dll"); // specify a file name where module will be stored

...

var baseType = baseTypeBuilder.CreateType();
var derivedType = derivedTypeBuilder.CreateType();

assembly.Save("Test.dll");
Run Code Online (Sandbox Code Playgroud)

现在我能够毫无例外地获取属性:

var attribute = baseType.GetCustomAttribute<XmlIncludeAttribute>();
Run Code Online (Sandbox Code Playgroud)