среда, 10 февраля 2016 г.

.NET(C#) для 1С. Динамическая компиляция класса обертки для использования .Net событий в 1С через ДобавитьОбработчик или ОбработкаВнешнегоСобытия

Динамическая компиляция класса обертки для использования .Net событий в 1С через ДобавитьОбработчик или ОбработкаВнешнегоСобытия, а так же генерация модулей на C# и 1С для подключения к событиям. Использование DynamicMethod и ILGenerator. Представлены примеры для использовании событий System.IO.FileSystemWatcher (Ожидает уведомления файловой системы об изменениях и инициирует события при изменениях каталога или файла в каталоге.) и SerialPort (обработка сканера штрих кода подключенного к COM порту). Обертка позволяет использовать классы .Net только на языке 1С.Реализация 1C Messenger описанного здесь http://catalog.mista.ru/public/434771/
Эта статья является дополнением разработки Использование сборок .NET в 1С 7.x b 8.x находящейся здесь http://catalog.mista.ru/public/238584/

Как то раз пришлось написать интеграцию 1С с WhatsApp. А там порядка 30 событий.
В ручную это делать было муторно как для обертки событий, так и для использования их в 1С.
Не поленился и написал кодогенератор.
Рассмотрим генерацию кода на примере System.IO.FileSystemWatcher
https://msdn.microsoft.com/ru-ru/library/system.io.filesystemwatcher(v=vs.110).aspx

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;


[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("6821a54a-19a2-4e66-85d9-e65396958080")]
public interfaceIВрапперДляSystem_IO_FileSystemWatcher
{

    [DispId(0x00000001)]
    void ОшибкаСобытия(Stringсобытиеobject value, objectисключение);
    [DispId(0x00000002)]
    void Changed(object value);
    [DispId(0x00000003)]
    void Created(object value);
    [DispId(0x00000004)]
    void Deleted(object value);
    [DispId(0x00000005)]
    void Error(object value);
    [DispId(0x00000006)]
    void Renamed(object value);
    [DispId(0x00000007)]
    void Disposed(object value);

}


[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("c3919804-ff5f-4d2a-a773-5067a1e051e1")]
[ComSourceInterfaces(typeof(IВрапперДляSystem_IO_FileSystemWatcher))]
public class ВрапперДляSystem_IO_FileSystemWatcher
{

    [ComVisible(false)]
    public delegate void Событие_Delgate();
    [ComVisible(false)]
    public delegate void СобытиеСПараметром_Delgate(object value);
    [ComVisible(false)]
    public  delegate void СобытиеСПараметрами_Delgate(Stringсобытиеobject value, objectисключение);

    public System.IO.FileSystemWatcher РеальныйОбъект;
    dynamic AutoWrap;
    private SynchronizationContext Sc;
    public event СобытиеСПараметрами_DelgateОшибкаСобытия;
    public Exception ПоследняяОшибка;
    public event СобытиеСПараметром_Delgate Changed;
    public event СобытиеСПараметром_Delgate Created;
    public event СобытиеСПараметром_Delgate Deleted;
    public event СобытиеСПараметром_Delgate Error;
    public event СобытиеСПараметром_Delgate Renamed;
    public event СобытиеСПараметром_Delgate Disposed;

    privateObject thisLock = newObject();


    void ОтослатьСобытие(Событие_Delgate Событие, string ИмяСобытия)
    {


        Task.Run(() =>
        {
            if (Событие !null//Событие();
            {
                lock (thisLock)
                {

                    try
                    {
                        Sc.Send(d => Событие(), null);
                    }

                    catch (Exception ex)
                    {
                        try
                        {

                            Sc.Send(d => ОшибкаСобытия(ИмяСобытияnullAutoWrap.ОбернутьОбъект(ex)), null);
                        }
                        catch (Exception)
                        {
                        }

                    }
                }
            }
        });
    }

    voidОтослатьСобытиеСПараметром(СобытиеСПараметром_DelgateСобытиеobject value, stringИмяСобытия)
    {
        Task.Run(() =>
        {


            if (Событие != null//Событие();
            {
                lock (thisLock)
                {
                    try
                    {
                        Sc.Send(d => Событие(AutoWrap.ОбернутьОбъект(value)), null);
                    }
                    catch (Exception ex)
                    {
                        try
                        {

                            Sc.Send(d => ОшибкаСобытия(ИмяСобытияAutoWrap.ОбернутьОбъект(value), AutoWrap.ОбернутьОбъект(ex)), null);
                        }
                        catch (Exception)
                        {
                        }
                    }

                }
            }
        });


    }
    publicВрапперДляSystem_IO_FileSystemWatcher(object AutoWrapSystem.IO.FileSystemWatcher РеальныйОбъект)
    {

        if (SynchronizationContext.Current == null)
            SynchronizationContext.SetSynchronizationContext(newWindowsFormsSynchronizationContext());

        Sc = SynchronizationContext.Current;


        this.РеальныйОбъект = РеальныйОбъект;
        this.AutoWrap = AutoWrap;
        РеальныйОбъект.Changed += (sender, e) =>
        {

            ОтослатьСобытиеСПараметром(Changed, new sender = sender, e = e }, "Changed");
        };

        РеальныйОбъект.Created += (sendere) =>
        {

            ОтослатьСобытиеСПараметром(Created, new sender = sender, e = e }, "Created");
        };

        РеальныйОбъект.Deleted += (sendere) =>
        {

            ОтослатьСобытиеСПараметром(Deleted, new sender = sender, e = e }, "Deleted");
        };

        РеальныйОбъект.Error += (sender, e) =>
        {

            ОтослатьСобытиеСПараметром(Error, new sender = sender, e = e }, "Error");
        };

        РеальныйОбъект.Renamed += (sender, e) =>
        {

            ОтослатьСобытиеСПараметром(Renamed, new sender = sender, e = e }, "Renamed");
        };

        РеальныйОбъект.Disposed += (sender, e) =>
        {

            ОтослатьСобытиеСПараметром(Disposed, new sender = sender, e = e }, "Disposed");
        };


    }

    publicstaticobjectСоздатьОбъект(object AutoWrapSystem.IO.FileSystemWatcher РеальныйОбъект)
    {

        returnnewВрапперДляSystem_IO_FileSystemWatcher(AutoWrapРеальныйОбъект);
    }
}


Так для упрощения, если параметров больше одного они упаковываются в анонимный класс.
Для вызова событий вызывается один из двух метод для всех событий с параметром и без.

Для вызова события в 1С используется SynchronizationContextдля вызова в потоке 1С приложения.
Используется синхронизация на всякий случай и при возникновении ошибки при вызове метода 1С вызывается событие ОшибкаСобытия, так как такие ошибки 1С 8.х не отлавливает без секции попытка-исключение.
Параметры оборачиваются в объект типа AutoWrap  с помощью  AutoWrap.ОбернутьОбъект для использования объектов Net как объектов автоматизации
Модуль для 8 ки формируется такой

Перемврап,ОберткаСобытий;

Процедура СоздатьОбертку(объект)
 
//Динамически компилируется модуль C#
ОберткаСобытий=врап.СоздатьОберткуДляСобытий(объект);
// Добавляются обработчики
ДобавитьОбработчик ОберткаСобытий.ОшибкаСобытия,ОшибкаСобытия;


ДобавитьОбработчик ОберткаСобытий.Changed, Changed;
ДобавитьОбработчик ОберткаСобытий.Created, Created;
ДобавитьОбработчик ОберткаСобытий.Deleted, Deleted;
ДобавитьОбработчик ОберткаСобытий.Error, Error;
ДобавитьОбработчик ОберткаСобытий.Renamed, Renamed;
ДобавитьОбработчик ОберткаСобытий.Disposed, Disposed;
КонецПроцедуры
// Дается описание параметров, чтобы было проще к ним обращаться


//ИмяСобытия:String Имя События в котором произошло исключение
//Данные:object Параметры события
//ИсключениеСобытия:Exception Ошибка произошедшая при вызове события
Процедура ОшибкаСобытия(ИмяСобытия,Данные,ИсключениеСобытия)
    Сообщить("Не обработано событие "+ИмяСобытия);
     Сообщить(" Исключение "+Врап.ВСтроку(ИсключениеСобытия));
 Сообщить(" Данные "+Врап.ВСтроку(Данные));
            КонецПроцедуры
//  параметр Данные:Аннимный Тип
                       // Свойства параметра
// sender:System.Object
// e:System.IO.FileSystemEventArgs

            Процедура Changed(Данные)
               Сообщить("Changed "+Врап.ВСтроку(Данные));
            КонецПроцедуры

//  параметр Данные:Аннимный Тип
                       // Свойства параметра
// sender:System.Object
// e:System.IO.FileSystemEventArgs

            Процедура Created(Данные)
               Сообщить("Created "+Врап.ВСтроку(Данные));
            КонецПроцедуры

//  параметр Данные:Аннимный Тип
                       // Свойства параметра
// sender:System.Object
// e:System.IO.FileSystemEventArgs

            Процедура Deleted(Данные)
               Сообщить("Deleted "+Врап.ВСтроку(Данные));
            КонецПроцедуры

//  параметр Данные:Аннимный Тип
                       // Свойства параметра
// sender:System.Object
// e:System.IO.ErrorEventArgs

            Процедура Error(Данные)
               Сообщить("Error "+Врап.ВСтроку(Данные));
            КонецПроцедуры

//  параметр Данные:Аннимный Тип
                       // Свойства параметра
// sender:System.Object
// e:System.IO.RenamedEventArgs

            Процедура Renamed(Данные)
               Сообщить("Renamed "+Врап.ВСтроку(Данные));
            КонецПроцедуры

//  параметр Данные:Аннимный Тип
                       // Свойства параметра
// sender:System.Object
// e:System.EventArgs

            Процедура Disposed(Данные)
               Сообщить("Disposed "+Врап.ВСтроку(Данные));
            КонецПроцедуры

Так как в 7.7 нет возможности использования комовских событий, сделал обертку с использование вызова IAsyncEvent метода ExternalEvent


using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;

[Guid("ab634004-f13d-11d0-a459-004095e1daea"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
publicinterfaceIAsyncEvent
{
    void SetEventBufferDepth(int lDepth);
    void GetEventBufferDepth(refint plDepth);
    void ExternalEvent(string bstrSourcestring bstrMessagestring bstrData);
    void CleanBuffer();
}

publicclassВрапперДляSystem_IO_FileSystemWatcher77
{
    System.IO.FileSystemWatcher РеальныйОбъект;
    publicobject Changed;
    publicobject Created;
    publicobject Deleted;
    publicobject Error;
    publicobject Renamed;
    publicobject Disposed;


    dynamic AutoWrap;
    privateSynchronizationContext Sc;
    IAsyncEventСобытиеДля1С;
    privateObject thisLock = newObject();
    publicobjectПоследняяОшибка;
    publicВрапперДляSystem_IO_FileSystemWatcher77(object AutoWrapObjectГлобальныйКонтекстSystem.IO.FileSystemWatcher РеальныйОбъект)
    {

        СобытиеДля1С = ГлобальныйКонтекстasIAsyncEvent;
        if (SynchronizationContext.Current == null)
            SynchronizationContext.SetSynchronizationContext(newWindowsFormsSynchronizationContext());

        Sc = SynchronizationContext.Current;


        this.РеальныйОбъект = РеальныйОбъект;
        this.AutoWrap = AutoWrap;
        РеальныйОбъект.Changed += (sender, e) =>
        {
            Changed = new { sender = sender, e = e };
            ОтослатьСобытие("Changed");
        };

        РеальныйОбъект.Created += (sender, e) =>
                    {
                        Created = new { sender = sender, e = e };
                        ОтослатьСобытие("Created");
                    };

        РеальныйОбъект.Deleted += (sender, e) =>
                    {
                        Deleted = new { sender = sender, e = e };
                        ОтослатьСобытие("Deleted");
                    };

        РеальныйОбъект.Error += (sender, e) =>
                    {
                        Error = new { sender = sender, e = e };
                        ОтослатьСобытие("Error");
                    };

        РеальныйОбъект.Renamed += (sender, e) =>
                    {
                        Renamed = new { sender = sender, e = e };
                        ОтослатьСобытие("Renamed");
                    };

        РеальныйОбъект.Disposed += (sender, e) =>
                    {
                        Disposed = new { sender = sender, e = e };
                        ОтослатьСобытие("Disposed");
                    };



    }

    voidОтослатьСобытие(stringИмяСобытия)
    {


        Task.Run(() =>
        {

            lock (thisLock)
            {

                try
                {
                    Sc.Send(d => СобытиеДля1С.ExternalEvent("System_IO_FileSystemWatcher"ИмяСобытия""), null);
                }

                catch (Exception ex)
                {
                    try
                    {
                        ПоследняяОшибка = new Событие = ИмяСобытия, Исключение = ex };
                        Sc.Send(d => СобытиеДля1С.ExternalEvent("System_IO_FileSystemWatcher""ОшибкаСобытия"""), null);
                    }
                    catch (Exception)
                    {
                    }

                }
            }

        });
    }

    publicstaticobjectСоздатьОбъект(object AutoWrapObjectГлобальныйКонтекстSystem.IO.FileSystemWatcher РеальныйОбъект)
    {

        returnnewВрапперДляSystem_IO_FileSystemWatcher77(AutoWrapГлобальныйКонтекстРеальныйОбъект);
    }
}


Для каждого события с параметром, параметрами создается одноименное поле и при возникновении события можно из 1С обратиться к этим полям.
Отмечу, что в данном случае объекты не оборачиваются в AutoWrap, так как обертка возвращается как AutoWrapПоясню чуть позже
Перемврап,ОберткаСобытий;

Функция СоздатьОбертку(ОбертываемыйОбъект)

// В NetObjetToIDispatch.dllреализованклассВКpublicclassGlobalContext1C :IInitDone, ILanguageExtender

//для получения глобального контекста при вызове

// publicvoid Init([MarshalAs(UnmanagedType.IDispatch)]
//     object connection)
//    {
//        глобальныйКонтекст = connection;
//        Marshal.GetIUnknownForObject(глобальныйКонтекст);
//  }

 
    ПодключитьВнешнююКомпоненту("AddIn.GlobalContext1C");
    объект = СоздатьОбъект("AddIn.GlobalContext1C");
    ГлобальныйКонтекст= объект.ГлобальныйКонтекст;

    ОберткаСобытий= врап.СоздатьОберткуДляСобытий77(ОбертываемыйОбъект,ГлобальныйКонтекст);
КонецФункции // СоздатьОбертку



// Свойства ОберткаСобытий.ПоследняяОшибка
//Событие:String Имя События в котором произошло исключение
//Данные:object Параметры события
//ИсключениеСобытия:Exception Ошибка произошедшая при вызове события
Функция ОшибкаСобытия()
    ПоследняяОшибка=ОберткаСобытий.ПоследняяОшибка;
    Сообщить("Не обработано событие "+ПоследняяОшибка.Событие);
    Сообщить(Врап.ВСтроку(Шаблон("[ОберткаСобытий." + ПоследняяОшибка.Событие+ "]")));
    Сообщить("Ошибка");
    Сообщить(врап.ВСтроку(ПоследняяОшибка.Исключение))
КонецФункции
//  Свойства ОберткаСобытий.Changed
// sender:System.Object
// e:System.IO.FileSystemEventArgs

Функция Changed()
    Сообщить("Changed "+Врап.ВСтроку(ОберткаСобытий.Changed));
КонецФункции

//  Свойства ОберткаСобытий.Created
// sender:System.Object
// e:System.IO.FileSystemEventArgs

Функция Created()
    Сообщить("Created "+Врап.ВСтроку(ОберткаСобытий.Created));
КонецФункции

//  Свойства ОберткаСобытий.Deleted
// sender:System.Object
// e:System.IO.FileSystemEventArgs

Функция Deleted()
    Сообщить("Deleted "+Врап.ВСтроку(ОберткаСобытий.Deleted));
КонецФункции

//  Свойства ОберткаСобытий.Error
// sender:System.Object
// e:System.IO.ErrorEventArgs

Функция Error()
    Сообщить("Error "+Врап.ВСтроку(ОберткаСобытий.Error));
КонецФункции

//  Свойства ОберткаСобытий.Renamed
// sender:System.Object
// e:System.IO.RenamedEventArgs

Функция Renamed()
    Сообщить("Renamed "+Врап.ВСтроку(ОберткаСобытий.Renamed));
КонецФункции

//  Свойства ОберткаСобытий.Disposed
// sender:System.Object
// e:System.EventArgs

Функция Disposed()
    Сообщить("Disposed "+Врап.ВСтроку(ОберткаСобытий.Disposed));
КонецФункции




Процедура ПриОткрытии()
    врап=СоздатьОбъект("NetObjectToIDispatch45");

КонецПроцедуры // ПриОткрытии
//======================================================================
Процедура ОбработкаВнешнегоСобытия(Источник, ИмяСобытия, Данные)
    Если Источник = "System_IO_FileSystemWatcher" Тогда

        Шаблон("[" + ИмяСобытия+ "()]");
    КонецЕсли;
КонецПроцедуры // ОбработкаВнешнегоСобытия


Динамическая компиляция происходит следующим образом

publicclassКомВраперДляСобытий<T>
        {
        privatestaticMethodInfo cоздательОбертки = null;
        privatestaticMethodInfo cоздательОбертки77 = null;

       staticCompilerResultsСкомпилироватьОбертку(stringстрокаКласса,stringИмяКласса)
        {
           
          
            boolЭтоСборкаГак = typeof(T).Assembly.GlobalAssemblyCache;
            stringПуть = Path.GetDirectoryName(typeof(T).Assembly.Location);
           


            string OutputAssembly = Path.Combine(ПутьИмяКласса) + ".dll";
       
         
            var compiler = newCSharpCodeProvider();
            var parameters = newCompilerParameters();

            parameters.ReferencedAssemblies.Add("System.dll");
            parameters.ReferencedAssemblies.Add("System.Core.dll");
            parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
            parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
            parameters.ReferencedAssemblies.Add(typeof(AutoWrap).Assembly.Location);

            if (!ЭтоСборкаГак)
                parameters.ReferencedAssemblies.Add(typeof(T).Assembly.Location);
            else
            {
                stringИмяСборки = typeof(T).Assembly.ManifestModule.Name;
                if (parameters.ReferencedAssemblies.IndexOf(ИмяСборки) == -1)
                    parameters.ReferencedAssemblies.Add(ИмяСборки);


            }

            if (ЭтоСборкаГак)
                parameters.GenerateInMemory = true;
            else
            //  parameters.GenerateInMemory = true;
                parameters.GenerateInMemory = false;
                parameters.OutputAssembly = OutputAssembly;
            }

            parameters.GenerateExecutable = false;
            parameters.IncludeDebugInformation = true;

            var res = compiler.CompileAssemblyFromSource(parameters, строкаКласса);
            return res;
        }
        publicstaticMethodInfoСоздательОбертки { get {
                if (cоздательОбертки==null)
                {
                    TypeтипРеальногоОбъекта = typeof(T);
                    stringТипСтрРеальногоОбъекта = типРеальногоОбъекта.FullName;
                    varИмяКласса = "ВрапперДля" + ТипСтрРеальногоОбъекта.Replace(".""_").Replace("+""_");
                   string  строкаКласса = ДляСозданияМодуляВрапераоздатьОписания(типРеальногоОбъекта);
                    var res = СкомпилироватьОбертку(строкаКласса,ИмяКласса);

                    Typeтип = res.CompiledAssembly.GetType(ИмяКласса);
                    MethodInfo mi = тип.GetMethod("СоздатьОбъект"newType[]{typeof(object),типРеальногоОбъекта });
                   
                    cоздательОбертки = mi;
                }

                return cоздательОбертки;
            } }

        publicstaticMethodInfoСоздательОбертки77
        {
            get
            {
                if (cоздательОбертки77 == null)
                {
                    TypeтипРеальногоОбъекта = typeof(T);
                    stringТипСтрРеальногоОбъекта = типРеальногоОбъекта.FullName;
                    varИмяКласса = "ВрапперДля" + ТипСтрРеальногоОбъекта.Replace(".""_").Replace("+""_")+"77";
                    string строкаКласса = ДляСозданияМодуляВрапераоздатьОписания77(типРеальногоОбъекта);
                    var res = СкомпилироватьОбертку(строкаКлассаИмяКласса);

                    Typeтип = res.CompiledAssembly.GetType(ИмяКласса);
                    MethodInfo mi = тип.GetMethod("СоздатьОбъект"newType[] { typeof(object), typeof(object), типРеальногоОбъекта });

                    cоздательОбертки77 = mi;
                }

                return cоздательОбертки77;
            }
        }

Так, чтобы лишний раз не компилировать, закэшируем результат компиляции через свойство дженерик класса. Реализацию этого класса Net будет создавать при первом обращении, а статические поля будем заполнять компиляцией динамически создаваемого модуля на C# только раз для каждого типа.
Так, для GAC сборок можно компилировать сборку в памяти. Для не гаковских сборок нужно указывать путь, где лежит сборка оборачиваемого типа.

Вызов из 1С происходит с помощью 2 методов СоздатьОберткуДляСобытий или СоздатьОберткуДляСобытий77
MethodInfo ПолучитьMethodInfoОберткиСобытий(string ИмяСвойстваobject РеальныйОбъект)
        {

//      получаем дженерик тип КомВраперДляСобытий<> и указывем тип

            Type тип = РеальныйОбъект.GetType();
            Type genType = typeof(КомВраперДляСобытий<>);
            Type constructed = genType.MakeGenericType(newType[] { тип });

            // Nowнаходим свойство и получаем его значение
            PropertyInfo pi = constructed.GetProperty(ИмяСвойства);
            MethodInfoфункция = (MethodInfo)pi.GetValue(nullnull);
            returnфункция;

        }
        publicobjectСоздатьОберткуДляСобытий(objectобъект)
        {

            object РеальныйОбъект = AutoWrap.ПолучитьРеальныйОбъект(объект);
            var функция = ПолучитьMethodInfoОберткиСобытий("СоздательОбертки"РеальныйОбъект);
            object обертка = функция.Invoke(null,newobject[] this,РеальныйОбъект });
// Возвращаем реальный объект, так как он является COM объектом
            return обертка;

        }
        publicobject СоздатьОберткуДляСобытий77(object объект, object ГлобальныйКонтекст)
        {

            object РеальныйОбъект = AutoWrap.ПолучитьРеальныйОбъект(объект);
            var функция = ПолучитьMethodInfoОберткиСобытий("СоздательОбертки77"РеальныйОбъект);
            object обертка = функция.Invoke(nullnewobject[] {ГлобальныйКонтекстеальныйОбъект });
// Оборачиваем обертку событий в AutoWrap для использования в 1С как объекта автоматизации
            returnAutoWrap.ОбернутьОбъект(обертка);

        }

Кроме того, можно использовать DynamicMethod. В отличие от динамической компиляции сборки,  определяет и представляет динамический метод, который может быть скомпилирован, выполнен и удалендаленные методы доступны для сборки мусора.

Так, в 1С нет операторов для битовых операций.  Для работы с FileSystemWatcher
Нам нужно определить события которые мы хотим отслеживать. На C# это выглядит так.
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                   NotifyFilters.FileName | NotifyFilters.DirectoryName;

Создадим функцию в C# проекте
publicstaticNotifyFilters OR(NotifyFilters val1, NotifyFilters val2)
        {

            return val1 | val2;
        }
Скомпилирует
В ILSpyнайдемнашметодивыберемязыкдекомпиляции IL
.method public hidebysig static 
    valuetype [System]System.IO.NotifyFilters OR (
        valuetype [System]System.IO.NotifyFilters val1,
        valuetype [System]System.IO.NotifyFilters val2
    ) cil managed 
{
    // Method begins at RVA 0x20cc
    // Code size 9 (0x9)
    .maxstack 2
    .locals init (
        [0] valuetype [System]System.IO.NotifyFilters
    )

    IL_0000: nop
    IL_0001: ldarg.0
    IL_0002: ldarg.1
    IL_0003: or
    IL_0004: stloc.0
    IL_0005: br.s IL_0007

    IL_0007: ldloc.0
    IL_0008: ret
// end of method MainWindow::OR

Для получения кода на MSIL можно использовать:
 Для рефлектора есть дизассемблер в Reflection.Emit, можно попытать щастья с expression trees (exp trees и emit состыковываются черезCompileToMethod)

Также рекомендую вводную серию статей — тынц.
Большая благодарность Sinix
Так, используя старый Reflector и плагин ReflectionEmitLanguage.zip  можно получить следующий код

publicMethodBuilder BuildMethodOR(TypeBuilder
type)
{
    // Declaring method builder
    // Method attributes
    System.Reflection.MethodAttributes methodAttributes = 
          System.Reflection.MethodAttributes.Public
        | System.Reflection.MethodAttributes.HideBySig
        | System.Reflection.MethodAttributes.Static;
    MethodBuildermethod = type.DefineMethod("OR", methodAttributes);
    // Preparing Reflection instances
    // Setting return type
    method.SetReturnType(typeof(NotifyFilters));
    // Adding parameters
    method.SetParameters(
        typeof(NotifyFilters),
        typeof(NotifyFilters)
        );
    // Parameter val1
    ParameterBuilderval1 =  method.DefineParameter(1, ParameterAttributes.None, "val1");
    // Parameter val2
    ParameterBuilderval2 =  method.DefineParameter(2, ParameterAttributes.None, "val2");
    ILGeneratorgen =  method.GetILGenerator();
    // Preparing locals
    LocalBuilderfilters =  gen.DeclareLocal(typeof(NotifyFilters));
    // Preparing labels
    Labellabel7 =  gen.DefineLabel();
    // Writing body
    gen.Emit(OpCodes.Nop);
    gen.Emit(OpCodes.Ldarg_0);
    gen.Emit(OpCodes.Ldarg_1);
    gen.Emit(OpCodes.Or);
    gen.Emit(OpCodes.Stloc_0);
    gen.Emit(OpCodes.Br_S,label7);
    gen.MarkLabel(label7);
    gen.Emit(OpCodes.Ldloc_0);
    gen.Emit(OpCodes.Ret);
    // finished
    return method;




Функция ПолучитьМетод()
  //"System.Func`3"

  NotifyFilters=врап.ПолучитьТип("System.IO.NotifyFilters");
  helloArgs=врап.СоздатьМассив(врап.ПолучитьТип("System.Type"),2);
  helloArgs.SetValue(NotifyFilters,0);
  helloArgs.SetValue(NotifyFilters,1);

  ТипДляМодуля=Врап.ТипКакОбъект(врап.ПолучитьТип("System.String"));
  hello= врап.СоздатьОбъект("System.Reflection.Emit.DynamicMethod","OR",
  NotifyFilters,
  helloArgs,
  ТипДляМодуля.Module);


  il= hello.GetILGenerator();


  il.DeclareLocal(NotifyFilters); 
  iL0007Label= il.DefineLabel();

  OpCodes=врап.ПолучитьТип("System.Reflection.Emit.OpCodes");
  
  il.Emit(OpCodes.Nop);
  il.Emit(OpCodes.Ldarg_0);
  il.Emit(OpCodes.Ldarg_1);

  il.Emit(OpCodes.Or);
  il.Emit(OpCodes.Stloc_0);
  il.Emit(OpCodes.Br_S, iL0007Label);
  il.MarkLabel(iL0007Label);
  il.Emit(OpCodes.Ldloc_0);
  il.Emit(OpCodes.Ret);
  тип = врап.ПолучитьТип("System.Func`3");
  типДелегата= Врап.ТипКакОбъект(тип).MakeGenericType(NotifyFilters,NotifyFilters,NotifyFilters);
  res= hello.CreateDelegate(типДелегата
  returnres

КонецФункции

Функция Или2(вал1,вал2)
  возврат врап.ВыполнитьДелегат(ДелегатИЛИ,вал1,вал2);
  //ДелегатИЛИ.DynamicInvoke(вал1,вал2);

КонецФункции// гл

Процедура КнопкаВыполнитьНажатие(Кнопка)
  // Вставить содержимое обработчика.
  Остановить();

    watcher= врап.СоздатьОбъект("System.IO.FileSystemWatcher, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
    Директория="c:\tmp\";
    watcher.Path= Директория;
       // Only watch text files.

    ДелегатИЛИ=ПолучитьМетод();
    NotifyFilters=врап.ПолучитьТип("System.IO.NotifyFilters");
//watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
    //        | NotifyFilters.FileName | NotifyFilters.DirectoryName;
    рез=Или2(NotifyFilters.LastAccess,Или2(NotifyFilters.LastWrite,Или2(NotifyFilters.FileName,NotifyFilters.DirectoryName)));
    watcher.NotifyFilter=рез;
    watcher.Filter= "*.*";
    watcher.IncludeSubdirectories= true;

    watcher.EnableRaisingEvents= true;

    СоздатьОбертку(watcher);


КонецПроцедуры


http://daveaglick.com/posts/compiler-platform-scripting






Процедура DataReceived(Данные)
    sp1 = Данные.sender;
    ШтрихКод= sp1.ReadExisting();
    Компорт= sp1.PortName;
    Сообщить(СтрШаблон("ШК=%1 Порт=%2",ШтрихКод,Компорт));

КонецПроцедуры

Источник: здесь

Комментариев нет:

Отправить комментарий