I need an alternative to `Assembly.GetEntryAssembly()` that never returns null

前端 未结 3 2062
时光取名叫无心
时光取名叫无心 2020-12-10 11:21

I need to find the assembly in which managed code execution started.

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


        
3条回答
  •  忘掉有多难
    2020-12-10 11:26

    I tried both methods of stakx.

    Method based on MainModule does not work in some special cases (dynamic assemblies for example).

    Method based on StackTrace can return an assembly too high (or low) in the hierarchy, like mscorlib.

    I made a little variant which works well in my use cases :

    // 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)
            ))
        {
            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.

提交回复
热议问题