我需要`Assembly.GetEntryAssembly()`从不返回null替代(I need

2019-07-17 20:28发布

我需要找到在托管代码执行开始组装。

// using System.Reflection;
Assembly entryAssembly = Assembly.GetEntryAssembly();

这似乎是要走的路,但对于MSDN参考页Assembly.GetEntryAssembly指出,这种方法“[C]从非托管代码调用时返回NULL。”

在这种情况下,我想知道哪些组件是由非托管代码调用。

是否有这样做的一个可靠的方法,即一个总是返回一个非空Assembly的参考?

Answer 1:

我能想到的迄今最好的是下面的,应在单线程情况下工作:

// using System.Diagnostics;
// using System.Linq; 
Assembly entryAssembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly;

(以上代码段为了便于理解,而不是用于执行速度或存储器效率最优化。)



Answer 2:

我想stakx的两种方法。

基于MainModule方法不起作用在某些特殊情况下(动态组件为例)。

基于堆栈跟踪方法可以在层次结构中返回一个组件太高(或低),如mscorlib程序。

我做了一点点变体在我的使用情况下效果很好:

// 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.Last();

Assembly entryAssembly = entryMethod.Module.Assembly;

基本上,我走栈,直到我找到一种常规方法使用名为“主” voidint返回类型。 如果没有找到这样的方法,我期待通过反射调用的方法。 例如,NUnit的使用该调用加载单元测试。

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



Answer 3:

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

// 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保证总是返回一个非空引用?



文章来源: I need an alternative to `Assembly.GetEntryAssembly()` that never returns null