![]() Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Позднее связывание
Традиционная постановка задачи позднего связывания может быть проиллюстрирована на следующем примере. Предположим, имеется программа, позволяющая выполнять обработку каких-либо файлов. Для обработки используются классы, реализующие интерфейс FileProcessor. Список типов обрабатываемых программой файлов и соответствующих им классов-обработчиков постоянно пополняется. Сборки, содержащие новые классы-обработчики, помещаются в отдельную папку, а программа-обработчик файлов должна уметь использовать всё новые и новые классы-обработчики без перекомпиляции. Интерфейс класса-обработчика будет иметь единственную функцию, определяющую, может ли данный класс обработать данный файл. Поместим интерфейс в отдельную сборку. На неё будут ссылаться конкретные классы-обработчики. Интерфейс-обработчик:
// compile with csc /t: library FileProcessor.cs using System; namespace FileProc { interface IFileProcessor { bool IsSupport(string filePath); } }
Теперь определим пару классов обработчиков. Пусть один из них будет работать с текстовыми файлами, второй – с картинками в формате ВMP. При этом каждый будет реализовывать интерфейс-обработчик, и будет помещён в отдельную сборку, ссылающуюся на сборку с интерфейсом. Обработчик текстовых файлов:
// compile with csc /t: library TextProcessor.cs /r: FileProcessor.cs using System; using FileProc; namespace TextProcessor { public class TextProcessor: IFileProcessor { override public bool IsSupport(string filePath) { return ".txt" == IO.Path.GetExtension(filePath).ToLower(); } } }
Обработчик картинок:
// compile with csc /t: library BmpProcessor.cs /r: FileProcessor.cs using System; using FileProc; namespace BmpProcessor { public class BmpProcessor: IFileProcessor { override public bool IsSupport(string filePath) { return ".bmp" == IO.Path.GetExtension(filePath).ToLower(); } } }
В самом приложении, осуществляющем позднее связывание с классами-обработчиками, просто загружаются все сборки из каталога приложения. Затем запрашиваются все типы из каждой сборки, и среди типов ищутся те, что унаследованы от абстрактного класса-обработчика. После того, как нужный тип найден, создаётся его экземпляр и вызывается метод IsSupport.
// compile with csc LateBind.cs /r: FileProcessor.cs using System; using System.IO; using System.Reflection; using FileProc;
namespace LateBind { class Class1 { [STAThread] //Атрибут static void Main(string[] args) { if(args.Length < 1) return; string[] files = Directory.GetFiles( System.Environment.CurrentDirectory, " *.dll"); foreach (string file in files) { Assembly assembly = Assembly.LoadFrom(file); Type[] types = assembly.GetTypes(); foreach (Type type in types) { if (typeof(IFileProcessor).IsAssignableFrom(type) & &! type.IsAbstract ) { IFileProcessor processor = (IFileProcessor)Activator.CreateInstance(type);
if (processor.IsSupport(args[0])) { Console.WriteLine( " Assembly {0} can process file {1}." , assembly.GetName().Name, args[0]); Console.ReadLine(); return; } } } } Console.WriteLine(" Can't process file {0}.", args[0]); Console.ReadLine(); } } }
Теперь, если появится необходимость обрабатывать файлы, например, формата VRML, не потребуется дорабатывать и перекомпилировать приложение. Достаточно будет разработать соответствующий класс-обработчик VRMLProcessor и поместить его в ту же папку, что и остальные классы-обработчики.
|