Поиск моего основного исполняемого пути с помощью Assembly vs AppDomain
Я пользователь .NET, и моя цель так же проста, как найти абсолютный путь к каталогу моей основной исполняющей сборки (EXE файл).
У меня есть несколько кандидатов:
-
Assembly.GetExecutingAssembly().CodeBase
-
Assembly.GetExecutingAssembly().Location
-
AppDomain.CurrentDomain.BaseDirectory
Если судить по документации .NET - я склоняюсь к CodeBase
.
Может ли кто-нибудь пролить свет на все три в несколько более конкретных терминах, чем на документацию .NET? Пример, чтобы продемонстрировать разницу, возможно?
Ответы
Ответ 1
Я использовал бы GetEntryAssembly()
вместо GetExecutingAssembly()
.
Чтобы узнать, почему, сделайте следующее:
- Создайте новый консольный проект
- Добавить проект библиотеки классов (
ClassLibrary1
) в решение и ссылаться на него из Консольного проекта.
Поместите это в ClassLibrary1
:
namespace ClassLibrary1
{
using System;
using System.IO;
using System.Reflection;
public class Class1
{
public void GetInfo(int n)
{
Assembly asm = Assembly.GetEntryAssembly();
Console.WriteLine("[GetEntryAssembly {0}] Location:{1}", n, Path.GetDirectoryName(asm.Location));
asm = Assembly.GetExecutingAssembly();
Console.WriteLine("[GetExecutingAssembly() {0}] Location:{1}", n, Path.GetDirectoryName(asm.Location));
}
}
}
Поместите это в консоль Program.cs
:
namespace ConsoleApplication4
{
using System;
using System.IO;
using System.Reflection;
using ClassLibrary1;
class Program
{
static void Main(string[] args)
{
Assembly asm = Assembly.GetEntryAssembly();
Console.WriteLine("[GetEntryAssembly() 1] Location:{0}", Path.GetDirectoryName(asm.Location));
asm = Assembly.GetExecutingAssembly();
Console.WriteLine("[GetExecutingAssembly() 1] Location:{0}", Path.GetDirectoryName(asm.Location));
Class1 obj1 = new Class1();
obj1.GetInfo(2);
asm = Assembly.LoadFile(@"C:\temp\ClassLibrary1.dll");
Type t = asm.GetType("ClassLibrary1.Class1");
object obj2 = asm.CreateInstance("ClassLibrary1.Class1");
t.GetMethod("GetInfo").Invoke(obj2, new object[] { 3 });
Console.ReadKey();
}
}
}
Создайте решение, скопируйте ClassLibrary1.dll
в c:\temp
и запустите.
Как вы увидите, GetExecutingAssembly()
может обмануть вас в определенных условиях.
Последнее замечание, если ваше приложение является Windows Forms, вы можете просто использовать Application.ExecutablePath
.
Ответ 2
Я не уверен в AppDomain.CurrentDomain.BaseDirectory
, но разница между Assembly.GetExecutingAssembly().CodeBase
и Assembly.GetExecutingAssembly().Location
была объяснена в этом сообщении в блоге.
CodeBase - это URL-адрес места, где был найден файл, а Location - это путь от того, где он был загружен. Например, если сборка была загружена из Интернета, ее CodeBase может начинаться с "http://", но ее местоположение может начинаться с "C: \". Если файл был скопирован теневым шрифтом, то Location будет путь к копии файла в директории shadow-copy.
Также хорошо знать, что CodeBase не гарантируется для сборок в GAC. Однако местоположение всегда будет установлено для сборок, загруженных с диска.
Итак, кажется, что ваш лучший выбор - Location
, если вам нужен реальный каталог, из которого был выполнен файл.
Ответ 3
К сожалению, все описанные выше методы могут потерпеть неудачу, если вы используете такую виртуализацию, как postbuild XenoCode.
Я проверил множество методов и нашел другое решение здесь.
Я обнаружил, что только
System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe"
возвращает правильное имя исполняемого файла.
Таким образом, объединяя имя файла с контуром от Assembly.GetEntryAssembly().Location
, вы получите правильный путь к исполняемому файлу.
Ответ 4
От: http://msdn.microsoft.com/en-us/library/system.reflection.assembly.codebase.aspx
Assembly.CodeBase
Чтобы получить абсолютный путь к загруженному манифеста, используйте Assembly.Location
.
Если сборка была загружена как байт массив, используя перегрузку нагрузки метод, который принимает массив байтов, это свойство возвращает местоположение вызывающий метод, а не расположение загруженной сборки.
Для AppDomain.CurrentDomain.BaseDirectory
, я честно понятия не имею о различиях с практической точки зрения.
Ответ 5
Использовать System.Linq
string MainExecutablePath= (System.Diagnostics.Process.GetProcesses().First(P =>P.MainWindowTitle == "MainExecutable'sWindowName")).MainModule.FileName.ToString();