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

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

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

В наличии

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

Категория:

Описание

 Эта статья является дополнением разработки Использование сборок .NET в 1С 7.x b 8.x находящейся здесь //sale.itcity.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 interface IВрапперДля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;

 

    private Object thisLock = newObject();

 

 

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

    {

 

 

        Task.Run(() =>

        {

            if (Событие != null) //Событие();

            {

                lock (thisLock)

                {

 

                    try

                    {

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

                    }

 

                    catch (Exception ex)

                    {

                        try

                        {

 

                            Sc.Send(d => ОшибкаСобытия(ИмяСобытия, null, AutoWrap.ОбернутьОбъект(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 AutoWrap, System.IO.FileSystemWatcher РеальныйОбъект)

    {

 

        if (SynchronizationContext.Current == null)

            SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

 

        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»);

        };

 

 

    }

 

    public static object СоздатьОбъект(object AutoWrap, System.IO.FileSystemWatcher РеальныйОбъект)

    {

 

        return new ВрапперДля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)]

public interface IAsyncEvent

{

    void SetEventBufferDepth(int lDepth);

    void GetEventBufferDepth(refint plDepth);

    void ExternalEvent(string bstrSource, string bstrMessage, string bstrData);

    void CleanBuffer();

}

 

public class ВрапперДляSystem_IO_FileSystemWatcher77

{

    System.IO.FileSystemWatcher РеальныйОбъект;

    publicobject Changed;

    publicobject Created;

    publicobject Deleted;

    publicobject Error;

    publicobject Renamed;

    publicobject Disposed;

 

 

    dynamic AutoWrap;

    private SynchronizationContext Sc;

    IAsyncEvent СобытиеДля1С;

    privateObject thisLock = newObject();

    public object ПоследняяОшибка;

    public ВрапперДляSystem_IO_FileSystemWatcher77(object AutoWrap, ObjectГлобальныйКонтекст, System.IO.FileSystemWatcher РеальныйОбъект)

    {

 

        СобытиеДля1С = ГлобальныйКонтекст as IAsyncEvent;

        if (SynchronizationContext.Current == null)

            SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

 

        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)

                    {

                    }

 

                }

            }

 

        });

    }

 

    public static object СоздатьОбъект(object AutoWrap, Object ГлобальныйКонтекст, System.IO.FileSystemWatcher РеальныйОбъект)

    {

 

        return new ВрапперДля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" Тогда

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

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

 

public class КомВраперДляСобытий<T>

        {

        private static MethodInfo cоздательОбертки = null;

        private static MethodInfo cоздательОбертки77 = null;

 

       static CompilerResults СкомпилироватьОбертку(string строкаКласса,string ИмяКласса)

        {

           

          

            bool ЭтоСборкаГак = typeof(T).Assembly.GlobalAssemblyCache;

            string Путь = Path.GetDirectoryName(typeof(T).Assembly.Location);

           

 

 

            string OutputAssembly = Path.Combine(Путь, ИмяКласса) + «.dll«;

       

         

            var compiler = new CSharpCodeProvider();

            var parameters = new CompilerParameters();

 

            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;

        }

        public static MethodInfo СоздательОбертки { get {

                if (cоздательОбертки==null)

                {

                    Type типРеальногоОбъекта = typeof(T);

                    string ТипСтрРеальногоОбъекта = типРеальногоОбъекта.FullName;

                    var ИмяКласса = «ВрапперДля« + ТипСтрРеальногоОбъекта.Replace(«.», «_»).Replace(«+», «_»);

                   string  строкаКласса = ДляСозданияМодуляВрапера.СоздатьОписания(типРеальногоОбъекта);

                    var res = СкомпилироватьОбертку(строкаКласса,ИмяКласса);

 

                    Type тип = res.CompiledAssembly.GetType(ИмяКласса);

                    MethodInfo mi = тип.GetMethod(«СоздатьОбъект«, new Type[]{typeof(object),типРеальногоОбъекта });

                   

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

                }

 

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

            } }

 

        public static MethodInfo СоздательОбертки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(«СоздатьОбъект«, new Type[] { 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(new Type[] { тип });

 

            // Nowнаходим свойство и получаем его значение

            PropertyInfo pi = constructed.GetProperty(ИмяСвойства);

            MethodInfo функция = (MethodInfo)pi.GetValue(null, null);

            return функция;

 

        }

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

        {

 

            object РеальныйОбъект = AutoWrap.ПолучитьРеальныйОбъект(объект);

            var функция = ПолучитьMethodInfoОберткиСобытий(«СоздательОбертки«, РеальныйОбъект);

            object обертка = функция.Invoke(null,new object[] { this,РеальныйОбъект });

// Возвращаем реальный объект, так как он является COM объектом

            return обертка;

 

        }

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

        {

 

            object РеальныйОбъект = AutoWrap.ПолучитьРеальныйОбъект(объект);

            var функция = ПолучитьMethodInfoОберткиСобытий(«СоздательОбертки77», РеальныйОбъект);

            object обертка = функция.Invoke(null, new object[] {ГлобальныйКонтекст,РеальныйОбъект });

// Оборачиваем обертку событий в AutoWrap для использования в 1С как объекта автоматизации

            return AutoWrap.ОбернутьОбъект(обертка);

 

        }

 

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

 

Так, в 1С нет операторов для битовых операций.  Для работы с FileSystemWatcher

Нам нужно определить события которые мы хотим отслеживать. На C# это выглядит так.

watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite

                   | NotifyFilters.FileName | NotifyFilters.DirectoryName;

 

Создадим функцию в C# проекте

public static NotifyFilters 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)

Также рекомендую вводную серию статей — тынц.

http://rsdn.ru/forum/dotnet/6235398.1

Большая благодарность Sinix

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

 

public MethodBuilder 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;

 

 

 

И соответственно напишем это все на языке 1С

Функция ПолучитьМетод()
  //"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);


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

 

Так полностью можно исключить внешние сборки. Мало того, сейчас на подходе релиз scripting api.

https://github.com/dotnet/roslyn/tree/master/src/Scripting/Core
Вот неплохое введение, всю серию статей можно смело читать, вредным не будет.

https://joshvarty.wordpress.com/2015/10/15/learn-roslyn-now-part-14-intro-to-the-scripting-api/

UPD. И ещё статья вдогонку.

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

То есть вместо IL можно использовать

 

has been added to your cart:
Оформление заказа