Российский Государственный Технологический Университет им. К.Э. Циолковского
Опубликован: 02.03.2007 | Доступ: свободный | Студентов: 5636 / 790 | Оценка: 3.96 / 3.45 | Длительность: 27:04:00
ISBN: 978-5-9556-0086-4
Лекция 10:

Атрибуты, сборки, рефлексия

Класс сборки в действии

Исследование свойств и областей применения класса Assembly начинаем с создания тестовой однофайловой сборки AssemblyForStart в рамках проекта Class Library.

Первая сборка Operators00.exe:

using System;
 namespace Operators00
 {
 public class xPoint
 {
 float x, y;
 xPoint()
 {
 x = 0.0F;
 y = 0.0F;
 }

public xPoint(float xKey, float yKey):this()
 {
 x = xKey;
 y = yKey;
 }

public static bool operator true(xPoint xp)
 {
 if (xp.x != 0.0F && xp.y != 0.0F) return true;
 else return false;
 }

public static bool operator false(xPoint xp)
 {
 if (xp.x == 0.0F || xp.y == 0.0F) return false;
 else return true;
 }


public static xPoint operator | (xPoint key1, xPoint key2)
 {
 if (key1) return key1;
 if (key2) return key2;
 return new xPoint();	
 }

public static xPoint operator & (xPoint key1, xPoint key2)
 {
 if (key1 && key2) return new xPoint(1.0F, 1.0F);
 return new xPoint();	
 }


public void Hello()
 {
 Console.WriteLine("Hello! Point {0},{1} is here!",this.x,this.y);	
 }
 }

class Class1
 {

 // The main entry Point for the application.

 static void Main() // У точки входа пустой список параметров.
 // Я пока не сумел ей передать через метод Invoke массива строк. 
 {
 xPoint xp0 = new xPoint(1.0F, 1.0F);	 
xPoint xp1 = new xPoint(1.0F, 1.0F);

if (xp0 || xp1) Console.WriteLine("xp0 || xp1 is true!");
 else Console.WriteLine("xp0 || xp1 is false!");
 }
 }
 }
Листинг 10.3.

Вторая сборка AssemblyForStart.dll. В примере она так и не запускалась. Используется только для тестирования стандартных средств загрузки сборок – библиотек классов:

using System;
 namespace AssemblyForStart
 {
 // Class1 : первая компонента сборки AssemblyForStart. 

public class Class1
 {
 public Class1()
 {
 Console.WriteLine("This is constructor Class1()");
 }

public void fC1()
 {
 Console.WriteLine("This is fC1()");
 }
 } 
 }

А вот полигон AssemblyStarter.exe. В примере демонстрируется техника ПОЗДНЕГО СВЯЗЫВАНИЯ. Именно поэтому код, который выполняется после загрузки сборки, не содержит в явном виде информации об используемых в приложении типах:

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

namespace AssemblyStarter
 {

 // Приложение обеспечивает запуск сборки.

class Class1
 {

static void Main(string[] args)
 {
 // Сборка может быть вызвана непосредственно по имени
 // (строковый литерал с дружественным именем сборки).
 // Ничего особенного. Просто имя без всяких там расширений.
 // Главная проблема заключается в том, что сборки должны 
 // предварительно включаться в раздел References (Ссылки).
 // Кроме того, информация о загружаемой сборке может быть представлена
 // в виде объекта - представителя класса AssemblyName, ссылка 
 // на который также может быть передана в качестве аргумента методу 
 // Assembly.Load().
 // Вот здесь как раз и происходит формирование этого самого объекта. 
 AssemblyName asmName = new AssemblyName();
 asmName.Name = "AssemblyForStart";
 // Версию подсмотрели в манифесте сборки с помощью IlDasm.exe.
 Version v = new Version("1.0.1790.25124");
 // Можно было бы для пущей крутизны кода поле Version 
 // проинициализировать непосредственно (дело хозяйское):
 // asmName.Version = new Version("1:0:1790:25124");
 asmName.Version = v;

 // Ссылка на объект - представитель класса Assembly.
 // 
Assembly asm = null;
 try
 {
 // Загрузка сборки по "дружественному имени". 
 //asm = Assembly.Load("AssemblyForStart");
 // Путь и полное имя при загрузке частной сборки не имеют значения.
 // Соответствующие файлы должны располагаться непосредственно
 // в каталоге приложения. 
 //asm = Assembly.Load
 //(@"D:\Users\WORK\Cs\AssemblyTest\AssemblyForStart\bin\Debug\ AssemblyForStart.dll");
 //asm = Assembly.Load(asmName);
 // Если сборку организовать в виде исполняемого модуля и
 // "запихнуть" в каталог вручную – загрузится и такая сборка.
 asm = Assembly.Load("Operators00");
 }
 catch(FileNotFoundException e)
 {
 Console.WriteLine("We have a problem:" + e.Message);
 }

 // Итак, решено. Загрузили сборку, содержащую объявление класса xPoint.
 // Если сборка загрузилась – с ней надо что-то делать. Ясное дело,
 // надо выполнять программный код сборки.
 // Первый вариант выполнения. В сборке содержатся объявления двух классов:
 // класса xPoint и класса Class1. Мы воспользуемся объявлением класса 
 // xPoint, построим соответствующий объект - представитель этого класса, 
 // после чего будем вызывать нестатические методы - члены этого класса.
 // Все происходит в режиме ПОЗДНЕГО связывания.
 // Поэтому ни о каких ЯВНЫХ упоминаниях
 // имен типов не может быть речи.
 // Единственное явное упоминание – это упоминание
 // имени метода.
 object[] ps = {25,25};
 Type[] types = asm.GetTypes();
 // Здесь используется класс Activator! 
object obj = Activator.CreateInstance(types[0],ps);

MethodInfo mi = types[0].GetMethod("Hello");
 mi.Invoke(obj,null);

 // Второй вариант выполнения. Воспользуемся тем обстоятельством,
 // что загружаемая сборка не является библиотекой классов, а является
 // обычной выполнимой сборкой с явным образом обозначенной точкой
 // входа – СТАТИЧЕСКОЙ функцией Main(), которая является членом 
 // класса Class1.
 mi = asm.EntryPoint;
 // Вот, все получилось! Единственное, что я не сделал,
 // так это не смог передать в точку входа загруженной
 // сборки массива строк-параметров (смотреть на точку входа данной 
 // сборки). Ну не удалось. Потому и в сборке
 // Operators точку входа сборки объявил без параметров. 
mi.Invoke(null,null);
 }
 }
 }
Листинг 10.4.

Собрали, запустили. Получилось. Стало быть, ВСЕ ХОРОШО.

В ходе выполнения приложения класс Assembly позволяет:

  • получать информацию о самой сборке;
  • обращаться к членам класса, входящим в сборку;
  • загружать другие сборки.

Разбор полетов

В приведенном выше примере демонстрируется техника ПОЗДНЕГО СВЯЗЫВАНИЯ. Именно поэтому код, который выполняется после загрузки сборки, не содержит в явном виде информации об используемых в приложении типах. Транслятор действует в строгом соответствии с синтаксисом языка C# и просто не поймет пожелания "создать объект – представитель класса ..., который будет объявлен в сборке, которую предполагается загрузить в ходе выполнения приложения".

Класс System.Activator

Класс Activator – главное средство, обеспечивающее позднее связывание.

Содержит методы, позволяющие создавать объекты на основе информации о типах, получаемой непосредственно в ходе выполнения приложения, а также получать ссылки на существующие объекты. Далее приводится список перегруженных статических методов класса:

  • CreateComInstanceFrom. Создает экземпляр COM-объекта;
  • CreateInstance. Создает объект – представитель specified-типа, используя при этом наиболее подходящий по списку параметров конструктор (best matches the specified parameters).

    Пример:

    ObjectHandle hdlSample;
     IMyExtenderInterface myExtenderInterface;
     string argOne = "Value of argOne";
     int argTwo = 7;
     object[] args = {argOne, argTwo};
     // Uses the UrlAttribute to create a remote object.
     object[] activationAttributes =
     {new UrlAttribute("http://localhost:9000/MySampleService")};
     // Activates an object for this client.
     // You must supply a valid fully qualified assembly name here.
     hdlSample = Activator.CreateInstance(
     "Assembly text name, Version, Culture, PublicKeyToken",
     "samplenamespace.sampleclass", 
    true,
     BindingFlags.Instance|BindingFlags.Public,
     null,
     args,
     null,
     activationAttributes,
     null);
     myExtenderInterface = (IMyExtenderInterface)hdlSample.Unwrap();
     Console.WriteLine(myExtenderInterface.SampleMethod("Bill"));
  • CreateInstanceFrom. Создает объект – представитель типа, специфицированного по имени. Имя специфицируется на основе имени сборки. При этом используется подходящий по списку параметров конструктор (the constructor that best matches the specified parameters).

    Пример:

    ObjectHandle hdlSample;
     IMyExtenderInterface myExtenderInterface;
     object[] activationAttributes = {new SynchronizationAttribute()};
     // Assumes that SampleAssembly.dll exists in the same directory as this assembly.
     hdlSample = Activator.CreateInstanceFrom(
     "SampleAssembly.dll",
     "SampleNamespace.SampleClass",
     activationAttributes);
     // Assumes that the SampleClass implements an interface provided by
     // this application.
     myExtenderInterface = (IMyExtenderInterface)hdlSample.Unwrap();
     Console.WriteLine(myExtenderInterface.SampleMethod("Bill"));
  • GetObjectOverloaded. Создает прокси (заместителя, представителя) для непосредственного запуска активизированного сервером объекта или XML-сервиса.

Сборка может быть вызвана непосредственно по имени (строковый литерал с дружественным именем сборки).

Ничего особенного. Просто имя без всяких там расширений. Главная проблема заключается в том, что частные сборки должны предварительно включаться в раздел References (Ссылки).

Кроме того, информация о загружаемой сборке может быть представлена в виде объекта – представителя класса AssemblyName, ссылка на который также может быть передана в качестве аргумента методу Assembly.Load().

kewezok kewezok
kewezok kewezok
Елена Шляхт
Елена Шляхт
Объясните плиз в чем отличие а++ от ++а
Почему результат разный?
int a=0, b=0;
Console.WriteLine(a++); //0
Console.WriteLine(++b); //1
a++;
++b;
Console.WriteLine(a); //2
Console.WriteLine(b); //2