如何获取代码所在的程序集路径?

Geo*_*uer 746 .net c# reflection

有没有办法获取当前代码所在的程序集的路径?我不想要调用程序集的路径,只需要包含代码的路径.

基本上我的单元测试需要读取一些相对于dll的xml测试文件.无论测试dll是从TestDriven.NET,MbUnit GUI还是其他东西运行,我都希望路径始终正确解析.

编辑:人们似乎误解了我的要求.

我的测试库位于说

C:\项目\ MyApplication的\ daotests\BIN \调试\ daotests.dll

我想得到这条道路:

C:\项目\ MyApplication的\ daotests\BIN \调试\

当我从MbUnit Gui运行时,到目前为止这三个建议都让我失望:

  • Environment.CurrentDirectory 给出c:\ Program Files\MbUnit

  • System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location 给出C:\ Documents and Settings\george\Local Settings\Temp\....\DaoTests.dll

  • System.Reflection.Assembly.GetExecutingAssembly().Location 与前一个相同.

Joh*_*bly 996

我已经定义了以下属性,因为我们经常在单元测试中使用它.

public static string AssemblyDirectory
{
    get
    {
        string codeBase = Assembly.GetExecutingAssembly().CodeBase;
        UriBuilder uri = new UriBuilder(codeBase);
        string path = Uri.UnescapeDataString(uri.Path);
        return Path.GetDirectoryName(path);
    }
}
Run Code Online (Sandbox Code Playgroud)

Assembly.Location在使用NUnit(其中程序集从临时文件夹运行)时,该属性有时会给你一些有趣的结果,所以我更喜欢使用CodeBase它以URI格式提供路径,然后在开头UriBuild.UnescapeDataString删除它File://,并将其GetDirectoryName更改为正常的Windows格式.

  • 这有一个我遇到的问题,如果你的目录名是:c:\ My%20Directory那么Uri.UnescapeDataString将返回:c:\ My Directory这意味着File.Exists("c:\ My Directory\MyFile.txt ")将返回false,因为正确的路径实际上是"c:\ My%20Directory\MyFile.txt"我遇到了这个,因为我们的SVN路径中有空格,当我们检查它们时,它会对空格进行编码. (27认同)
  • `CodeBase` 已经过时了。“Assembly.Location”是首选替代方案。 (10认同)
  • 使用它来检查File.Exist()时要小心,因为此方法将在UNC路径上返回false.请改用@ Keith的答案. (5认同)
  • 注意:这不适用于网络位置(例如\\ REMOT_EPC\Folder) (5认同)
  • 如果目录中有数字符号'#',这也不起作用.Windows中的目录和文件名中允许使用数字符号. (4认同)
  • 不知道你可以在公众面前放静电.很高兴知道,我认为我更喜欢可读性 (3认同)
  • 该死的,对我来说仍然无法工作:0(现在不是它给我MSBuild路径,我得到TeamCity C的路径:\ TeamCity\buildAgent\temp\buildTmp\SYSTEM_SVR1 2010-08-24 17_34_23\Out但是另一个获得路径的方式:-) (2认同)
  • 我已经使用这种方法很多年了,但是当有问题的目录路径包含一个“#”时,今天却失败了。 (2认同)
  • CodeBase 在 .net core 中已弃用:https://learn.microsoft.com/en-us/dotnet/api/system.reflection. assembly.codebase?view=net-5.0 。请参阅下面的我的答案/sf/answers/4383829201/ (2认同)

Kei*_*ith 312

这有帮助吗?

//get the full location of the assembly with DaoTests in it
string fullPath = System.Reflection.Assembly.GetAssembly(typeof(DaoTests)).Location;

//get the folder that's in
string theDirectory = Path.GetDirectoryName( fullPath );
Run Code Online (Sandbox Code Playgroud)

  • 或者只是`typeof(DaoTests).Assembly` (21认同)
  • @SLaks @JohnySkovdal @Keith:嘿伙计们,使用`Assembly.GetExecutingAssembly()`.它_"获取包含当前正在执行的代码的程序集"_(来自方法描述).我在我的AddIn"[EntitiesToDTOs](http://entitiestodtos.codeplex.com)"中使用它.有关实例,请参阅[AssemblyHelper.cs](https://entitiestodtos.svn.codeplex.com/svn/EntitiesToDTOs/EntitiesToDTOs/Helpers/AssemblyHelper.cs). (4认同)
  • @John Silby的帖子有问题,因为它看起来不适用于UNC路径...例如\\ Server\Folder\File.ext.这个就行了.+1 (4认同)
  • 将xml文件设置为内​​容,使用dll或资源进行复制,从dll中读取. (3认同)
  • 我个人会使用这样的方法:`public static string GetAssemblyDirectory<T>(){return System.IO.Path.GetDirectoryName(typeof(T).Assembly.Location);}` (2认同)

Jal*_*aer 306

这很简单:

var dir = AppDomain.CurrentDomain.BaseDirectory;
Run Code Online (Sandbox Code Playgroud)

  • 不,这是错的.这将返回ORIGINAL ENTRY POINT的路径,而不是当前正在执行的代码.如果已从其他路径手动加载程序集,或者已从GAC加载程序集,则会返回错误的结果.这个答案是正确的:http://stackoverflow.com/a/283917/243557更快仍然是`Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)`. (115认同)
  • 这应该是公认的解决方案.AppDomain.CurrentDomain.BaseDirectory是正确的方法. (11认同)
  • 实际上这不适用于Web应用程序,但据我发现,以下扩充应适用于任何类型的应用程序:`AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory` (9认同)
  • 我希望原来的切入点如此完美 (8认同)
  • 谢谢你把我的注意力还给了这个 - 不确定当我问这个问题时它是否可用,但现在是. (5认同)
  • 如果您只想获得测试装配的原始bin路径(例如,到达子文件夹中的辅助数据文件),这对于单元测试非常有用.测试程序集是代码的入口点. (3认同)

Sne*_*eal 66

与John的答案相同,但是一种稍微冗长的扩展方法.

public static string GetDirectoryPath(this Assembly assembly)
{
    string filePath = new Uri(assembly.CodeBase).LocalPath;
    return Path.GetDirectoryName(filePath);            
}
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

var localDir = Assembly.GetExecutingAssembly().GetDirectoryPath();
Run Code Online (Sandbox Code Playgroud)

或者如果您愿意:

var localDir = typeof(DaoTests).Assembly.GetDirectoryPath();
Run Code Online (Sandbox Code Playgroud)

  • 你的意思是'assembly`而不是`Assembly.GetExecutingAssembly()`? (6认同)
  • 对于手头的问题,这个答案是完全错误的.此答案的修改版本可以为您提供给定程序集的路径.但是,在这里,我们专门寻找正在执行的程序集,因此传入程序集是没有意义的.扩展方法是该作业的错误工具. (4认同)
  • 正如Dude指出的那样,你传递了一个论点并且未能使用它. (3认同)

Ign*_*cia 46

使用CodeBase和UNC Network共享时,唯一有效的解决方案是:

System.IO.Path.GetDirectoryName(new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);
Run Code Online (Sandbox Code Playgroud)

它也适用于普通的URI.

  • 这应该是公认的答案.默认代码库不能正确处理UNC共享真的很烦人. (5认同)

jod*_*ell 32

除非程序集是阴影复制,否则这应该有效:

string path = System.Reflection.Assembly.GetExecutingAssembly().Location
Run Code Online (Sandbox Code Playgroud)


Ily*_*dik 19

我相信这适用于任何类型的应用程序:

AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory
Run Code Online (Sandbox Code Playgroud)

  • 我的实验表明,这是最简单的答案,不仅涵盖 Web 和控制台应用程序,还涵盖来自单元测试和 NuGet 包(嵌套到任何级别的递归)的调用。 (3认同)

hus*_*int 14

那这个呢:

System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Run Code Online (Sandbox Code Playgroud)


Cur*_*her 11

我怀疑这里真正的问题是你的测试运行器正在将你的程序集复制到另一个位置.在运行时无法确定程序集的复制位置,但您可以翻转一个开关,告诉测试运行程序从何处运行程序集,而不是将其复制到影子目录.

当然,对于每个测试跑步者来说,这种切换可能是不同的.

您是否考虑将XML数据作为资源嵌入测试程序集中?


小智 11

AppDomain.CurrentDomain.BaseDirectory
Run Code Online (Sandbox Code Playgroud)

适用于MbUnit GUI.


Mar*_*ade 7

var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyPath = assembly.GetFiles()[0].Name;
var assemblyDir = System.IO.Path.GetDirectoryName(assemblyPath);
Run Code Online (Sandbox Code Playgroud)


Mik*_*all 7

这是John Sibly代码的VB.NET端口.Visual Basic不区分大小写,因此他的一些变量名称与类型名称冲突.

Public Shared ReadOnly Property AssemblyDirectory() As String
    Get
        Dim codeBase As String = Assembly.GetExecutingAssembly().CodeBase
        Dim uriBuilder As New UriBuilder(codeBase)
        Dim assemblyPath As String = Uri.UnescapeDataString(uriBuilder.Path)
        Return Path.GetDirectoryName(assemblyPath)
    End Get
End Property
Run Code Online (Sandbox Code Playgroud)


spe*_*der 7

据我所知,大多数其他答案都有一些问题.

对基于磁盘(而不是基于Web)的非GACed程序集执行此操作的正确方法是使用当前正在执行的程序集的CodeBase属性.

这将返回一个URL(file://).而不是乱搞字符串操作,或者UnescapeDataString通过利用LocalPath属性来轻松转换Uri.

var codeBaseUrl = Assembly.GetExecutingAssembly().CodeBase;
var filePathToCodeBase = new Uri(codeBaseUrl).LocalPath;
var directoryPath = Path.GetDirectoryName(filePathToCodeBase);
Run Code Online (Sandbox Code Playgroud)


Dav*_*chs 7

这个怎么样 ...

string ThisdllDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Run Code Online (Sandbox Code Playgroud)

然后只是砍掉你不需要的东西


cub*_*e45 7

从 .net framework 4.6 / .net core 1.0 开始,现在有一个AppContext.BaseDirectory,它应该给出与 相同的结果AppDomain.CurrentDomain.BaseDirectory,除了 AppDomains 不是 .net core 1.x /.net 标准 1.x API 的一部分.

AppContext.BaseDirectory
Run Code Online (Sandbox Code Playgroud)

编辑:文档现在甚至声明:

在 .NET 5.0 及更高版本中,对于捆绑程序集,返回的值是主机可执行文件的包含目录。

事实上,Assembly.Location doc doc 说:

在 .NET 5.0 及更高版本中,对于捆绑程序集,返回的值为空字符串。


Geo*_*uer 6

这些年来,没有人真正提到这一个.我从一个很棒的ApprovalTests项目中学到了一个技巧.诀窍是您使用程序集中的调试信息来查找原始目录.

这不能在RELEASE模式下工作,也不能在启用优化的情况下工作,也不能在与编译它的机器不同的机器上工作.

但是这将获得相对于您调用它的源代码文件位置的路径

public static class PathUtilities
{
    public static string GetAdjacentFile(string relativePath)
    {
        return GetDirectoryForCaller(1) + relativePath;
    }
    public static string GetDirectoryForCaller()
    {
        return GetDirectoryForCaller(1);
    }


    public static string GetDirectoryForCaller(int callerStackDepth)
    {
        var stackFrame = new StackTrace(true).GetFrame(callerStackDepth + 1);
        return GetDirectoryForStackFrame(stackFrame);
    }

    public static string GetDirectoryForStackFrame(StackFrame stackFrame)
    {
        return new FileInfo(stackFrame.GetFileName()).Directory.FullName + Path.DirectorySeparatorChar;
    }
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*000 6

tl;博士

程序集和 DLL 文件的概念不同。根据程序集的加载方式,路径信息会丢失或根本不可用。不过,在大多数情况下,提供的答案会起作用。


这个问题和之前的答案存在一个误解。在大多数情况下,提供的答案可以正常工作,但在某些情况下,无法获得当前代码所在的程序集的正确路径。

程序集(包含可执行代码)和 dll 文件(包含程序集)的概念不是紧密耦合的。程序集可能来自 DLL 文件,但并非必须如此。

使用Assembly.Load(Byte[])( MSDN ) 方法可以直接从内存中的字节数组加载程序集。字节数组来自哪里并不重要。它可以从文件加载,从互联网下载,动态生成,...

这是一个从字节数组加载程序集的示例。文件加载后路径信息丢失。无法获得原始文件路径,并且之前描述的所有方法都不起作用。

此方法位于执行程序集中,该程序集位于“D:/Software/DynamicAssemblyLoad/DynamicAssemblyLoad/bin/Debug/Runner.exe”

static void Main(string[] args)
{
    var fileContent = File.ReadAllBytes(@"C:\Library.dll");

    var assembly = Assembly.Load(fileContent);

    // Call the method of the library using reflection
    assembly
        ?.GetType("Library.LibraryClass")
        ?.GetMethod("PrintPath", BindingFlags.Public | BindingFlags.Static)
        ?.Invoke(null, null);

    Console.WriteLine("Hello from Application:");
    Console.WriteLine($"GetViaAssemblyCodeBase: {GetViaAssemblyCodeBase(assembly)}");
    Console.WriteLine($"GetViaAssemblyLocation: {assembly.Location}");
    Console.WriteLine($"GetViaAppDomain       : {AppDomain.CurrentDomain.BaseDirectory}");

    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)

这个类位于 Library.dll 中:

public class LibraryClass
{
    public static void PrintPath()
    {
        var assembly = Assembly.GetAssembly(typeof(LibraryClass));
        Console.WriteLine("Hello from Library:");
        Console.WriteLine($"GetViaAssemblyCodeBase: {GetViaAssemblyCodeBase(assembly)}");
        Console.WriteLine($"GetViaAssemblyLocation: {assembly.Location}");
        Console.WriteLine($"GetViaAppDomain       : {AppDomain.CurrentDomain.BaseDirectory}");
    }
}

Run Code Online (Sandbox Code Playgroud)

为了完整起见,这里的实现GetViaAssemblyCodeBase()对于两个程序集都是相同的:

private static string GetViaAssemblyCodeBase(Assembly assembly)
{
    var codeBase = assembly.CodeBase;
    var uri = new UriBuilder(codeBase);
    return Uri.UnescapeDataString(uri.Path);
}

Run Code Online (Sandbox Code Playgroud)

Runner 打印以下输出:

Hello from Library:
GetViaAssemblyCodeBase: D:/Software/DynamicAssemblyLoad/DynamicAssemblyLoad/bin/Debug/Runner.exe
GetViaAssemblyLocation:
GetViaAppDomain       : D:\Software\DynamicAssemblyLoad\DynamicAssemblyLoad\bin\Debug\
Hello from Application:
GetViaAssemblyCodeBase: D:/Software/DynamicAssemblyLoad/DynamicAssemblyLoad/bin/Debug/Runner.exe
GetViaAssemblyLocation:
GetViaAppDomain       : D:\Software\DynamicAssemblyLoad\DynamicAssemblyLoad\bin\Debug\
Run Code Online (Sandbox Code Playgroud)

如您所见,代码库、位置或基本目录都不正确。


Dav*_*rab 5

您存在的当前目录.

Environment.CurrentDirectory;  // This is the current directory of your application
Run Code Online (Sandbox Code Playgroud)

如果您使用build复制.xml文件,您应该找到它.

要么

System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(SomeObject));

// The location of the Assembly
assembly.Location;
Run Code Online (Sandbox Code Playgroud)

  • 通常,CurrentDirectory不会告诉您可执行文件所在的位置.这不是它的用途.它恰好经常出现在可执行文件所在的位置,因此很多程序员都不了解其中的区别.然后他们最终为一些期望应用程序理解正确使用CurrentDirectory的最终用户造成麻烦. (4认同)

dan*_*son 5

我一直在使用Assembly.CodeBase而不是Location:

Assembly a;
a = Assembly.GetAssembly(typeof(DaoTests));
string s = a.CodeBase.ToUpper(); // file:///c:/path/name.dll
Assert.AreEqual(true, s.StartsWith("FILE://"), "CodeBase is " + s);
s = s.Substring(7, s.LastIndexOf('/') - 7); // 7 = "file://"
while (s.StartsWith("/")) {
    s = s.Substring(1, s.Length - 1);
}
s = s.Replace("/", "\\");
Run Code Online (Sandbox Code Playgroud)

它一直在工作,但我不再确定它是100%正确的.http://blogs.msdn.com/suzcook/archive/2003/06/26/assembly-codebase-vs-assembly-location.aspx上的页面说:

"CodeBase是找到文件的地方的URL,而Location是实际加载的路径.例如,如果程序集是从Internet下载的,它的CodeBase可能以"http://"开头. ,但它的位置可能以"C:\"开头.如果文件是阴影复制的,则位置将是阴影副本目录中文件副本的路径.知道CodeBase不能得到保证也很好要为GAC中的程序集设置.但是,总是会为从磁盘加载的程序集设置位置. "

可能希望使用CodeBase而不是Location.


小智 5

在 Windows 窗体应用程序中,您可以简单地使用Application.StartupPath

但对于 DLL 和控制台应用程序来说,代码更难记住......

string slash = Path.DirectorySeparatorChar.ToString();
string root = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

root += slash;
string settingsIni = root + "settings.ini"
Run Code Online (Sandbox Code Playgroud)