【问题标题】:Can't access CodeBase from a dynamically generated assembly无法从动态生成的程序集中访问 CodeBase
【发布时间】:2011-06-09 13:55:21
【问题描述】:

我正在尝试在 .Net 中动态创建程序集。但是,我似乎无法弄清楚如何让 CodeBase 属性返回一个值。这是一个例子:

var assemblyName = new AssemblyName
                        {
                            Name = "Whatever",
                            CodeBase = Directory.GetCurrentDirectory()
                        };
var assemblyBuilder = AppDomain.CurrentDomain
    .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("WhateverModule", "Whatever.dll");
var typeBuilder = moduleBuilder.DefineType("WhateverType", TypeAttributes.Public);
var type = typeBuilder.CreateType();
assemblyBuilder.Save("Whatever.dll");
var codeBase = type.Assembly.CodeBase; // throws the below exception

System.NotSupportedException was unhandled
  Message=The invoked member is not supported in a dynamic assembly.
  Source=mscorlib
  StackTrace:
       at System.Reflection.Emit.InternalAssemblyBuilder.get_CodeBase()
       at Stupid.Program.Main(String[] args) in C:\Users\Walking Disaster\Documents\Visual Studio 10\Projects\Lingual.Proxy\Stupid\Program.cs:line 25
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

谁能看出我做错了什么?

说明:我正在尝试使用在运行时生成测试方法的插件来扩展 NUnit。它通过获取一组 Action 委托来实现这一点。不幸的是,Reflection 已经深入到框架中,所以我不得不为每个 Action 委托发出带有方法的类。当我只使用 NUnitTestMethod 类时,这很好用,但是当我使用 NUnitTestFixture 时,它​​会失败,因为它试图从程序集中读取 CodeBase。我不想创建一个物理组件,但是这个项目是一个又一个的妥协。

【问题讨论】:

    标签: c# .net reflection reflection.emit


    【解决方案1】:

    我认为异常原因是 CodeBase 在动态汇编上毫无意义。来自 MSDN:

    最初指定的程序集位置

    如果你重新加载程序集,它不会抛出异常:

    var assemblyName = new AssemblyName
                           {
                               Name = "Whatever",
                               CodeBase = Directory.GetCurrentDirectory()
                           };
    var assemblyBuilder = AppDomain.CurrentDomain
        .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
    var moduleBuilder = assemblyBuilder.DefineDynamicModule(
        "WhateverModule", "Whatever.dll");
    var typeBuilder = 
                     moduleBuilder.DefineType("WhateverType", TypeAttributes.Public);
    var type = typeBuilder.CreateType();
    assemblyBuilder.Save("Whatever.dll");
    
    var assembly = Assembly.LoadFrom("Whatever.dll");
    var codeBase = assembly.CodeBase; // this won't throw exception
    

    【讨论】:

    • 我很害怕这个。我可能必须这样做才能完成,然后深入研究 NUnit 以尝试限制他们严重依赖反射造成的损害。
    【解决方案2】:

    大会的Location 有效吗?你可以分叉 NUnit 并使用它来代替你提到的损坏:P

    我已经花了几个小时来研究 NUnit 的“可扩展性”故事,无法想象曾经在 xUnit.net 上选择它 - 但我想决定因素将是你有多少测试......

    【讨论】:

    • 我和你在一起。我不敢相信 NUnit 选择通过反射获取所有测试元数据。不幸的是,这是针对现有项目的,我们已经进行了 7K+ NUnit 测试。我知道 xUnit 允许您运行 NUnit 测试,但是在接近项目完成时将其切换是不利的。不过,我正在考虑将我的工作移植到 xUnit 以用于下一个项目。
    • 我猜它不太可能适合,但你看过 RunWithNUnitAttribute [它允许你通过 xunit 运行器运行 NUnit 测试]。还没有看到任何示例,但您会惊讶于 xunit 中的示例是多么简洁和简洁(下载示例并查找 NUnitRunnerAcceptanceTests)? (是的,一个很长的镜头!)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-26
    • 1970-01-01
    相关资源
    最近更新 更多