65.9K
CodeProject 正在变化。 阅读更多。
Home

从 StackTrace 获取调用程序集

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2014 年 7 月 1 日

CPOL

2分钟阅读

viewsIcon

13903

downloadIcon

133

本文介绍了一种从被调用程序集获取调用测试程序集的便捷方法

引言

最近,我在开发一个类库时,该类库预计会被基于 NUnit 的一些测试库调用。在被调用库的 `static` 构造函数中实现了一些代码,用于解析测试库的类型,因此被调用函数首先需要知道外部调用程序集。

然而,Assembly.GetCallingAssembly() 总是会返回被调用库本身,因为 `static` 构造函数会在类的实例化之前自动调用。而 Assembly.GetEntryAssembly() 总是会返回 null,这可能是因为执行代码是由 NUnit 框架启动的。看来我需要将代码移动到调用测试库中,或者更改其背后的逻辑。

幸运的是,我注意到在 Visual Studio 的“调用堆栈”窗口中,调用序列非常清晰,所以我尝试使用 StackTrace 并获得了预期的结果。虽然这种方法很简单,但我在网上没有找到相关的讨论,所以可能其他人阅读这篇文章后可以节省时间来解决这个问题。

详细说明

获取调用程序集的代码非常简单

using System.Diagnostics;
using System.Reflection;

        private static Assembly callingAssemblyByStackTrace()
        {
            Assembly thisAssembly = Assembly.GetExecutingAssembly();

            StackTrace stackTrace = new StackTrace();
            StackFrame[] frames = stackTrace.GetFrames();

            foreach (var stackFrame in frames)
            {
                var ownerAssembly = stackFrame.GetMethod().DeclaringType.Assembly;
                if (ownerAssembly != thisAssembly)
                    return ownerAssembly;
            }
            return thisAssembly;
        }

此方法有意放置在 `static` 构造函数之外,如下所示

    public class Class1
    {
        private static Assembly callingAssemblyByStackTrace(){}

        static Class1()
        {
            Console.WriteLine("Assembly.GetExecutingAssembly() returns: " + 
                               Assembly.GetExecutingAssembly());
            Console.WriteLine("Assembly.GetEntryAssembly() returns: " + Assembly.GetEntryAssembly());
            Console.WriteLine("Assembly.GetCallingAssembly() returns: " + 
                               Assembly.GetCallingAssembly());

            Assembly callingAssembly = callingAssemblyByStackTrace();
            Console.WriteLine("The calling Assembly is " + callingAssembly);
        }

        public Class1(){}
    }

为了测试其功能,还有一个类库类型的项目引用了上述程序集和 NUnit,如下所示

    [TestFixture]
    public class TestClass
    {
        [Test]
        public void Test1()
        {
            Class1 class1 = new Class1();
        }
    }

因此,由 NUnit 运行的测试代码会实例化一个 Class1 对象,这将触发 static Class1(),后者会调用 callingAssemblyByStackTrace() 来获取输出

Assembly.GetExecutingAssembly() returns: AssemblyFromStackTrace, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Assembly.GetEntryAssembly() returns: 
Assembly.GetCallingAssembly() returns: AssemblyFromStackTrace, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
The calling Assembly is AssemblyFromStackTraceTest, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

AssemblyFromStackTraceTest 正是我所期望的。

Using the Code

压缩文件包含两个项目,将两者提取到一个文件夹中。AssemblyFromStackTraceTest 需要引用 AssemblyFromStackTrace 项目和 NUnit,运行它作为测试,就可以在控制台中看到上述输出。

© . All rights reserved.