我需要找到开始执行托管代码的程序集。
// using System.Reflection;
Assembly entryAssembly = Assembly.GetEntryAssembly();
这似乎是要走的路,但MSDN 参考页面Assembly.GetEntryAssembly
声明此方法“[c] 从非托管代码调用时返回 null”。
在这种情况下,我想知道非托管代码调用了哪个程序集。
是否有一种可靠的方法来执行此操作,即始终返回非空Assembly
引用的方法?
我需要找到开始执行托管代码的程序集。
// using System.Reflection;
Assembly entryAssembly = Assembly.GetEntryAssembly();
这似乎是要走的路,但MSDN 参考页面Assembly.GetEntryAssembly
声明此方法“[c] 从非托管代码调用时返回 null”。
在这种情况下,我想知道非托管代码调用了哪个程序集。
是否有一种可靠的方法来执行此操作,即始终返回非空Assembly
引用的方法?
到目前为止我能想到的最好的是以下,它应该在单线程场景中工作:
// using System.Diagnostics;
// using System.Linq;
Assembly entryAssembly = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly;
(上面的代码片段是为了易于理解而优化的,而不是为了执行速度或内存效率。)
我尝试了两种 stakx 方法。
基于 MainModule 的方法在某些特殊情况下不起作用(例如动态程序集)。
基于 StackTrace 的方法可能会返回层次结构中过高(或过低)的程序集,例如 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.LastOrDefault();
Assembly entryAssembly = entryMethod?.Module?.Assembly;
Basically, I walk the stack up until I find a conventional method named "Main" with void
or int
return type.
If no such method is found, I look for a method invoked via reflection. For example, NUnit uses that invocation to load unit tests.
Of course, I do that only if Assembly.GetEntryAssembly()
returns null
.
工作解决方案的另一个(基本上未经测试的)起点可能是这样的:
// 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
保证总是返回非空引用吗?