首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >我需要一个永远不返回null的`Assembly.GetEntryAssembly()‘的替代方法

我需要一个永远不返回null的`Assembly.GetEntryAssembly()‘的替代方法
EN

Stack Overflow用户
提问于 2013-01-04 22:08:34
回答 3查看 15.1K关注 0票数 27

我需要找到开始执行托管代码的程序集。

代码语言:javascript
运行
复制
// using System.Reflection;
Assembly entryAssembly = Assembly.GetEntryAssembly();

这似乎是要走的路,但是Assembly.GetEntryAssembly声明这个方法“当从非托管代码调用时可以返回null”。

在这种情况下,我想知道非托管代码调用了哪个程序集。

是否有一种可靠的方法来做到这一点,即总是返回一个非空Assembly引用?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-01-04 22:08:34

到目前为止,我能想到的最好的方法是以下几点,它应该可以在单线程的情况下工作:

代码语言:javascript
运行
复制
// using System.Diagnostics;
// using System.Linq; 
Assembly entryAssembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly;

(上面的片段是为便于理解而优化的,而不是为了执行速度或内存效率。)

票数 23
EN

Stack Overflow用户

发布于 2015-07-17 11:35:43

两种方法我都试过了。

基于MainModule的方法在某些特殊情况下不工作(例如动态程序集)。

基于StackTrace的方法可以在层次结构中返回太高(或太低)的程序集,比如mscorlib。

我制作了一个小变体,它在我的用例中工作得很好:

代码语言:javascript
运行
复制
// using System.Diagnostics;
// using System.Linq;
var methodFrames = new StackTrace().GetFrames().Select(t => t?.GetMethod()).ToArray();
MethodBase entryMethod = null;
int firstInvokeMethod = 0;
for (int i = 0; i < methodFrames.Length; i++)
{
    var method = methodFrames[i] as MethodInfo;
    if (method == null)
        continue;
    if (method.IsStatic &&
        method.Name == "Main" &&
        (
            method.ReturnType == typeof(void) || 
            method.ReturnType == typeof(int) ||
            method.ReturnType == typeof(Task) ||
            method.ReturnType == typeof(Task<int>)
        ))
    {
        entryMethod = method;
    }
    else if (firstInvokeMethod == 0 &&
        method.IsStatic &&
        method.Name == "InvokeMethod" &&
        method.DeclaringType == typeof(RuntimeMethodHandle))
    {
        firstInvokeMethod = i;
    }
}

if (entryMethod == null)
    entryMethod = firstInvokeMethod != 0 ? methodFrames[firstInvokeMethod - 1] : methodFrames.LastOrDefault();

Assembly entryAssembly = entryMethod?.Module?.Assembly;

基本上,我沿着堆栈向上走,直到找到一个名为“常规方法”的voidint返回类型。如果找不到这样的方法,我将查找通过反射调用的方法。例如,NUnit使用该调用来加载单元测试。

当然,只有当Assembly.GetEntryAssembly()返回null时,我才会这样做。

票数 11
EN

Stack Overflow用户

发布于 2013-01-04 23:08:17

另一个(主要是未经测试的)工作解决方案的起点可能是这样的:

代码语言:javascript
运行
复制
// using System;
// using System.Diagnostics;
// using System.Linq;
ProcessModule mainModule = Process.GetCurrentProcess().MainModule;
Assembly entryAssembly = AppDomain.CurrentDomain.GetAssemblies()
                         .Single(assembly => assembly.Location == mainModule.FileName);

一些不确定因素仍然存在:

  • 模块和程序集不是一回事。ProcessModule甚至在概念上可能与Module不同。上述代码是否总是在多模块(即多文件)程序集存在的情况下工作,特别是当程序集的入口点不在清单模块中时?
  • Process.MainModule保证总是返回一个非空引用吗?
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14165785

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档