This is a mirror of official site: http://jasper-net.blogspot.com/

Аспектно-ориентированное программирование, Mono.Cecil, MSIL, кодогенерация, изменение сборок и многое другое. Статья 1

| Monday, November 8, 2010
В данном цикле статей я расскажу про MSIL, кодогенерацию в .NET, изменение существующих сборок, Mono.Cecil, аспектно-ориентированное программирование и многое другое (если конечно вам это будет нужно:) ). Все это будет сопровождаться работающими примерами, так как я считаю, что код - это лучший способ донести идею. Это моя первая статья вообще, и на GotDotNet в частности, так что любые комментарии приветствуются. Цикл будет продолжаться, если это кого-либо заинтересует. Итак, начнем.
Многие .NET разработчики знают, что для доступа к объектам чужой сборки можно использовать Reflection. С помощью типов из System.Reflection мы можем получить доступ ко многим объектам .NET сборки, просмотреть их метаданные, и даже использовать те объекты, доступ к которым ограничен (например, private методы чужого класса). Но Reflection в .NET очень ограничен, и главная причина этому - данные, с котороми вы работаете через Reflection все еще считаются кодом. Таким образом, вы, к примеру, можете получить CodeAccessSecurity exception, если сборка, к которой вы пытаетесь применить Refelection, запрещает это. По этой же причине Reflection работает довольно медленно. Но наиболее важным для дальнейшего является то, что стандартный Reflection не позволяет изменять существующие сборки, только генерировать и сохранять новые.

Качественно иной подход предлагает бесплатная библиотека Mono.Cecil, поставляющаяся вместе с исходным кодом. Главное отличие Mono.Cecil от Reflection в том, что она рассматривает сборку как набор инструкций MSIL (как поток байт) , а не как некий код. Таким образом, с помощью Mono.Cecil можно как угодно изменять MSIL код имеющейся сборки.

Сразу рассмотрим на примере использование возможностей Mono.Cecil. Предположим, у нас есть консольное приложение без исходного кода, в котором есть тип Program. У нас нет доступа к исходному коду, но мы хотим, чтобы данное приложение при вызове каждого метода выводило,, на консоль некоторое сообщение. Для этого напишем собственное консольное приложение. В качестве аргумента при запуске будем передавать путь к целевому приложению:

using Mono.Cecil;
using Mono.Cecil.Cil;

class Program
{
 static void Main(string[] args)
 {
   if (args.Length == 0)
     return;
   string assemblyPath = args[0];
   // считываем сборку в формате Mono.Cecil
   var assembly = AssemblyDefinition.ReadAssembly(assemblyPath);
   // получаем метод Console.WriteLine, используя стандартные методы Reflection
   var writeLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
   // создаем ссылку на метод, полученный Reflection, для использования в Mono.Cecil
   var writeLineRef = assembly.MainModule.Import(writeLineMethod);
   foreach (var typeDef in assembly.MainModule.Types)
   {
     foreach (var method in typeDef.Methods)
     {
     // Для каждого метода в полученной сборке
     // Загружаем на стек строку "Inject!"
     method.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Ldstr, "Inject!"));
     // Вызываем метод Console.WriteLine, параметры он берет со стека - в данном случае строку "Injected".
     method.Body.Instructions.Insert(1, Instruction.Create(OpCodes.Call, writeLineRef));
     }

Read more: gotDotNet

Posted via email from .NET Info

0 comments: