Позднее связывание

80

Поздним связыванием (late binding) называется технология, которая позволяет создавать экземпляр определенного типа и вызывать его члены во время выполнения без кодирования факта его существования жестким образом на этапе компиляции. При создании приложения, в котором предусмотрено позднее связывание с типом из какой-то внешней сборки, добавлять ссылку на эту сборку нет никакой причины, и потому в манифесте вызывающего кода она непосредственно не указывается.

На первый взгляд увидеть выгоду от позднего связывания не просто. Действительно, если есть возможность выполнить раннее связывание с объектом (например, добавить ссылку на сборку и разместить тип с помощью ключевого слова new), следует обязательно так и поступать. Одна из наиболее веских причин состоит в том, что раннее связывание позволяет выявлять ошибки во время компиляции, а не во время выполнения. Тем не менее, позднее связывание тоже играет важную роль в любом создаваемом расширяемом приложении.

Класс System.Activator

Класс System. Activator (определенный в сборке mscorlib.dll) играет ключевую роль в процессе позднего связывания в .NET. В текущем примере интересует пока что только его метод Activator.CreateInstance(), который позволят создавать экземпляр подлежащего позднему связыванию типа. Этот метод имеет несколько перегруженных версий и потому обеспечивает довольно высокую гибкость. В самой простой версии CreateInstance() принимает действительный объект Type, описывающий сущность, которая должна размещаться в памяти на лету.

Чтобы увидеть, что имеется в виду, давайте создадим новый проект типа Console Application, импортируем в него пространства имен System.I0 и System.Reflection с помощью ключевого слова using и затем изменим класс Program, как-показано ниже:

using System;
using System.Reflection;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            Assembly ass = null;
            try
            {
                ass = Assembly.Load("fontinfo");
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine(ex.Message);
            }
            if (ass != null)
                CreateBinding(ass);
            Console.ReadLine();
        }

        static void CreateBinding(Assembly a)
        {
            try
            {
                Type color1 = a.GetType("FontColor");

                // Используем позднее связывание
                object obj = Activator.CreateInstance(color1);
                Console.WriteLine("Объект создан!");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

Прежде чем запускать данное приложение, необходимо вручную скопировать сборку fontinfo.dll в подкаталог bin\Debug внутри каталога этого нового приложения с помощью проводника Windows. Дело в том, что здесь вызывается метод Assembly.Load(), а это значит, что CLR-среда будет зондировать только папку клиента (при желании можно было бы воспользоваться методом Assembly.LoadFrom() и указывать полный путь к сборке, но в данном случае в этом нет никакой необходимости).

Добавлять ссылку на fontinfo.dll с помощью Visual Studio в данном примере тоже не следует! Это приведет к добавлению записи о данной библиотеке в манифест клиента. Вся суть применения позднего связывания состоит в том, чтобы попробовать создать объект, о котором на момент компиляции ничего не известно.

Обратите внимание, что метод Activator.CreateInstance() возвращает экземпляр объекта System.Object, а не строго типизированный объект. Следовательно, в случае применения к переменной obj операции точки никаких членов класса FontInfo увидеть не получится.

Лучший чат для C# программистов