Поиск моего основного исполняемого пути с помощью 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();