Приветствую всех, не секрет иногда все мы используем сторонние библиотеки, и порой нарушая их условия использования, скрываем в недрах нашего приложения. Или же мы просто не хотим таскать их за своим приложением exe, что бы они не мозолили глаза. В таком случаи мы можем их добавить в сборку и использовать методы и классы находящиеся внутри них. Сделать это можно следующим способом.
Добавляем dll в папку ресурсы:
Допусти мы имеет dll в моем случаи у нее содержимое такое:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
using System; using System.Windows.Forms; namespace MyClass { public class Class1 { public void MyMethod() { MessageBox.Show("www.nookery.ru"); } } } |
Теперь мы добавим нашу dll в новый проект, сделать это можно следующим образом:
Выделить наш проект, нажав правую кнопку мыши выбрать свойство.
Нажмите расширяющий значок треугольника и выберите Добавить существующий фаил. Теперь укажите ваш dll он добавится в ресурсы.
После чего вам нужно его сохранить, для этого выберите пункт меню Фаил и Сохранить выбранные элементы.
Теперь мы можем закрыть, это окно, а в обозревателе решений мы должны увидеть :
На этом все, наша dll находится внутри сборки, однако нам теперь нужно ее как то использовать, а вот для этого имеется несколько вариантов.
1. Вариант с помощью Рефлексии:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System; using System.Reflection; namespace nookery { class Program { static void Main(string[] args) { Assembly asm = Assembly.Load(nookery.Properties.Resources.MyClass); dynamic myClass = asm.CreateInstance("MyClass.Class1"); myClass.MyMethod(); Console.ReadKey(); } } } |
Не достатком такого варианта это отсутствие intellisense при работе с dll, нам необходимо знать метод вызываемый, класс и пространство имен. Хотя это можно узнать все и через Рефлексию, так же. Однако если проект очень большой и использует большое количество dll, может стать препятствием.
2. Вариант с помощью AppDomain подменить утерянные ссылки на dll.
- Первый вариант с использованием winform
У нас имеется тот же класс в dll :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
using System; using System.Windows.Forms; namespace MyClass { public class Class1 { public void MyMethod() { MessageBox.Show("www.nookery.ru"); } } } |
Описанным выше примере, мы добавляем в ресурсы dll, и указываем как обычно ссылку на ее месторасположения, продолжая работать словно так как будто ничего не предвещает.
Однако нам придется создать событие и обработать ее, пример ниже показывает как это сделать:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System; using System.Reflection; using System.Windows.Forms; using WindowsFormsApp19.Properties; namespace WindowsFormsApp19 { public partial class Form1 : Form { public Form1() { AppDomain.CurrentDomain.AssemblyResolve += AppDomain_AssemblyResolve; InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { MyClass.Class1 my = new MyClass.Class1(); //обычная работа с классом my.MyMethod(); //тут мы вызываем как обычно метод из dll } private static Assembly AppDomain_AssemblyResolve(object sender, ResolveEventArgs args) { if (args.Name.Contains("MyClass")) //имя dll return Assembly.Load(Resources.MyClass); //расположения dll в папке ресурсы return null; } } } |
Собираем проект, и переносим наш exe куда угодно. При запуске приложения сработает событие, из за того, что не был обнаружен фаил dll который мы указывали когда добавляли ссылку на него. И внутри обработчика событий у нас происходит подмена ссылок, а программа продолжает свою работу.
Не забудьте в свойствах dll изменить действие при сборке на Внедренный ресурс.
- Теперь рассмотрим другой вариант с Console:
Из за особенностей работы метода Main, а именно то что она начинает работать самым первым, в нем нельзя подписываться на событие иначе, обработка события не произойдет. Для решения этого есть два варианта либо так :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; using System.Reflection; using MyClass; using ConsoleApp51.Properties; namespace nookery { class Program { static Program(){ AppDomain.CurrentDomain.AssemblyResolve += AppDomain_AssemblyResolve; } private static void Main() { MyClass.Class1 my = new MyClass.Class1(); my.MyMethod(); Console.ReadKey(); } private static Assembly AppDomain_AssemblyResolve(object sender, ResolveEventArgs args) { if (args.Name.Contains("MyClass")) //имя dll return Assembly.Load(Resources.MyClass); //расположения dll в папке ресурсы return null; } } } |
используя статический конструктор, который отработает раньше метода Main
либо вот так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
using System; using System.Reflection; using ConsoleApp51.Properties; namespace nookery { class Program { private static void Main() { AppDomain.CurrentDomain.AssemblyResolve += AppDomain_AssemblyResolve; Test(); } public static void Test() { MyClass.Class1 my = new MyClass.Class1(); my.MyMethod(); } private static Assembly AppDomain_AssemblyResolve(object sender, ResolveEventArgs args) { if (args.Name.Contains("MyClass")) //имя dll return Assembly.Load(Resources.MyClass); //расположения dll в папке ресурсы return null; } } } |
Создав вспомогательный метод вынеся в него работу метода из dll
3. Выгрузить все DLL рядом с exe после запуска.
1 |
File.WriteAllBytes("MyClass.dll", ConsoleApp51.Properties.Resources.MyClass); |
1 2 |
[DllImport("MyClass.dll", SetLastError = true, EntryPoint = "MyMethod", ExactSpelling = true)] public static extern void MyMethod(); |
Однако этот вариант работает только с не управляемым кодом который написан на C++, и нам не походит.