Я написал небольшой проект в VS 2013, используя стороннюю библиотеку (DLL). Теперь рядом с экзешником приходится постоянно держать эту библиотеку. Нельзя ли встроить эту библиотеку в проект или хотя бы необходимую часть кода, что бы не приходилось повсюду таскать эту dllку?
-
@Vitokhv этот вопрос - полный дубликат вопроса по ссылке. Это точно такой же вопрос с точно такими же решениями (ресурсы + AssemblyResolve или ilmerge). Если это не так - покажите, что именно в вопросе отличается. По поводу стиля общения - перечитайте, пожалуйста, https://ru.stackoverflow.com/help/be-nice/. – Mar 08 '18 at 16:27
-
@Vitokhv ваш вопрос, кстати, тоже дубликат. как вам указали в комментариях, Ionic.Zip.Reduced.dll вшивается в exe точно так же - вшиванием в ресурсы или прогоном ilmerge. Нет никакой разницы, подключена dll как соседний проект или подключена через nuget. – Mar 08 '18 at 16:30
-
Объяснение простое, если бы Вы указали мой дубликат на эту тему, у меня бы отпали все вопросы. Но Вы почему то решили, что та тема главнее тех, которые действительно важны. Мне больше подходит ответ в этой теме, чем в другой. – Vitokhv Mar 08 '18 at 16:32
-
@Vitokhv это не "я решил" - это правила сайта - на одну конкретную проблему - один вопрос с ответами от нескольких участников. Тот ответ, который вам подошел больше - практически полная копия решения №2 из https://ru.stackoverflow.com/a/471236/177221 - тот же механизм, тот же обработчик, код отличается незначительными деталями. Да, детали важны - и механизим дубликатов как раз и существует для того, чтобы собрать в одном вопросе ответы от разных авторов. А не заставлять участников искать "подходящий ответ" по десятку одинаковых тем – Mar 08 '18 at 16:49
-
1@Vitokhv та тема выбрана как целевая для дубликата потому что она создана на пол года раньше, чем эта. Т.е. когда топикастер пришел сюда с вопросом - там уже был готовый ответ. Было бы наоборот - закрыли бы наоборот. – Mar 08 '18 at 16:51
3 Answers
Да, можно. Зависимую библиотеку можно встроить в ресурсы и подгружать оттуда вручную. Предполагается, что ваша библиотека уже находится в References проекта, проект собирается, программа успешно запускается.
Для начала добавьте в проект библиотеку как ресурс:
- Меню Project -> Add Existing Item... - выбираете вашу сборку (dll, в диалоге открытия выберите тип файлов Executable Files). Библиотека появится в списке файлов проекта.
- Вызовите контекстное меню на добавленном файле, выберите Properties. Затем установите в открывшемся окне Build Actions -> Embedded Resource.
Добавьте в ваш проект следующий класс:
public static class Resolver
{
private static volatile bool _loaded;
public static void RegisterDependencyResolver()
{
if (!_loaded) {
AppDomain.CurrentDomain.AssemblyResolve += OnResolve;
_loaded = true;
}
}
private static Assembly OnResolve(object sender, ResolveEventArgs args)
{
Assembly execAssembly = Assembly.GetExecutingAssembly();
string resourceName = String.Format("{0}.{1}.dll",
execAssembly.GetName().Name,
new AssemblyName(args.Name).Name);
using (var stream = execAssembly.GetManifestResourceStream(resourceName)) {
int read = 0, toRead = (int)stream.Length;
byte[] data = new byte[toRead];
do {
int n = stream.Read(data, read, data.Length - read);
toRead -= n;
read += n;
} while (toRead > 0);
return Assembly.Load(data);
}
}
}
Этот класс загрузит зависимую сборку из ресурса, как только основная программа обратится к ней, используя обработчик события AppDomain.AssemblyResolve.
В классе, где находится точка входа программы, добавьте статический конструктор и вызовите метод RegisterDependencyResolver.
Для примера, пусть у вас имеется консольное приложение:
class Program
{
static Program()
{
Resolver.RegisterDependencyResolver();
}
static void Main(string[] args)
{
// ...
}
}
Заботиться о выгрузке сборки не надо, т.к. это все равно невозможно (можно выгрузить только домен целиком).
Пример подсмотрен в книге Дж. Рихтера "CLR via C#".
- 6,159
-
-
1"stream.Read(data, 0, data.Length);" - кто-то гарантирует, что всё содержимое будет отдано сразу? – Qwertiy Apr 28 '16 at 07:51
-
-
Еще один вариант - использовать ILMerge. Но писать скрипт для "склеивания" придется вручную, интеграции со студией из коробки нет.
Также такой вариант будет работать не для любой библиотеки; если библиотека активно использует рефлексию - возможно потребуется написать свой обработчик AssemblyResolve:
var assembly = typeof(Program).Assembly;
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
if (args.Name == "имя внедренной сборки") return assembly;
return null;
};
Главное достоинство варианта с ILMerge при работе с несколькими проектами - не требуется помещать один и тот же код загрузчика в каждый проект; поскольку обработчик AssemblyResolve нужен только для рефлексии - можно поместить его в общую библиотеку.
- 58,537
Используйте утилиту ILMerge, а точнее ILMergeGUI Отличная утилита, упаковывает все DLL в EXE
- 3,586