Как задать структуру выходного проекта?

211
10 января 2018, 15:20

По умолчанию VS при компиляции кладет все в одну директорию рядом с EXE.

Т.е и сборки и все остальное лежат в одной папке.

Как создать свою собственную структуру?

Например, я хочу, что бы одни сборки клались в одну папку, другие в другую, а в корне был EXE.

Answer 1

Ну это как бы можно.

Для начала, вы добавляете каталоги, в которых будут лежать ваши библиотеки, в assembly probing path. Для этого отредактируйте ваш app.config, добавьте в него следующее:

<configuration>
   <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <probing privatePath="some\subfolder;another\subfolder"/>
      </assemblyBinding>
   </runtime>
</configuration>

(Документация.)

Затем, в свойствах проекта в зависимостях укажите CopyLocal = False:

Затем, в свойствах проекта-библиотеки установите Output Path в каталог, где вы хотите получить эту DLL (для каждого из ваших target platform/processor):

Ну или в post-build step каждого из зависимых проектов укажите вручную копирование куда надо.

Всё, должно работать.

Как советует @Andrew B в комментариях, существует ещё один путь, описанный в документации: подписаться на событие AssemblyResolve, которое отправляется, если .NET не может загрузить сборку из вашего каталога.

Для этого нужен код наподобие такого:

AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;

где метод OnAssemblyResolve определён так:

Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
    var name = args.Name.Substring(0, args.Name.IndexOf(","));
    // проверка на то, есть ли загружаемая сборка среди наших статических ссылок
    // взята из https://support.microsoft.com/ru-ru/kb/837908
    // но вам может быть и не нужна, подумайте сами
    if (!Assembly.GetExecutingAssembly().GetReferencedAssemblies()
                 .Any(asmName => asmName.FullName.Substring(0, asmName.FullName.IndexOf(","))
                                    == name))
    {
        // это не assembly из наших ссылок
        return null;
    }
    var applicationDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    foreach (var subfolder in new[] { @"some\subfolder", @"another\subfolder" })
    {
        var path = Path.Combine(applicationDir, subfolder, name + ".dll";
        if (File.Exists(path))
            return Assembly.LoadFrom(path);
    }
    return null;
}

(Не тестировал.)

Достоинство этого решения — то, что список путей можно изменять динамически, если это вдруг понадобилось.

Недостаток — то, что у вас некоторые сборки будут грузиться в assembly binding-контексте LoadFrom в отличие от обычной загрузки в контексте Load. Типы, загруженные в таком контексте, будут несовместимы с типами, загруженными в обычном контексте. Особенно это может «клюнуть», если у вас в разных местах лежат разные версии одной и той же сборки. [Это может привести к эффекту, когда один и тот же статический класс существует в двух экземплярах.] Будьте осторожны и готовы к неожиданностям! (Вопрос также обсуждался здесь.)

Если ваши сборки приходят с ресурсами, возможно, вам нужно учесть эту модификацию.

Дополнительное чтение по теме assembly binding/load context:

  • Best Practices for Assembly Loading
  • Suzanne Cook, LoadFile vs. LoadFrom

Для автоматического копирования сборок в целевые каталоги посредством MSBuild посмотрите ответы к этому вопросу.

Но в целом, я бы порекомендовал воспользоваться советом @TomTom и не заморачиваться, а оставить всё как есть. То, что файлы лежат в одном каталоге, пользователь не увидит, если вы правильным образом поместите ярлыки в системное меню при инсталляции (а вы в любом случае должны это сделать).

READ ALSO
C# Привязать свой scrollbar к TableLayoutPanel

C# Привязать свой scrollbar к TableLayoutPanel

Как привязать свой VScrollBar к TableLayout панели?

258
The property &#39;MarkId&#39; on entity type &#39;GameMarks&#39; has a temporary value

The property 'MarkId' on entity type 'GameMarks' has a temporary value

Доброе время суток всем, прошу прощение чье время отнимаюСуть в том, что после того, как добавил метки в EF Core и проапдейтил базу, я не могу добавить...

206
Удалить слушатель

Удалить слушатель

Assets/Scripts/TutorialControllercs(72,79): error CS0039: Cannot convert type void' toUnityEngine

175
Перемножение строк

Перемножение строк

Как правильно сделать перемножение string[] ?

252