Это продолжение статьи Кроссплатформенное использование классов .Net в 1С через Native ВК. Или замена COM на Linux II

В .Net сейчас во многих классах есть асинхронные методы. В 1С их можно применять например так

Стр=ъ(Клиент.GetStringAsync(uriSources)).Result;

И напомню про синонимы из предыдущей статьи/ Так добавив синоним

Врап.ДобавитьСиноним(HTTPClient.ПолучитьСсылку(),"ПолучитьСтроку","GetStringAsync");
Врап.ДобавитьСиноним(Task.ПолучитьСсылку(),"Результат","Result");

Я могу использовать все на русском

Стр=ъ(Клиент.ПолучитьСтроку(адрес)).Результат;

Но можно использовать асинхронные методы так.


        Клиент = ъ(Врап.Новый(HttpClient.ПолучитьСсылку(),handler.ПолучитьСсылку()));
	
	лист=ъНовый("System.Collections.Generic.List`1[System.Threading.Tasks.Task]");
	Для каждого стр из ПолучитьСписокURL() Цикл
		Задача=ъ(Клиент.GetStringAsync(стр));
		лист.Add(задача.ПолучитьСсылку()); 
	КонецЦикла;
	
	Task=ъТип("System.Threading.Tasks.Task");
	
	Пока лист.Count>0 Цикл
		массив=ъ(лист.ToArray());	
		индекс = Task.WaitAny(массив.ПолучитьСсылку());
		Сообщить(индекс);
		результат = ъ(лист.get_Item(индекс)).Result;
		Сообщить(СтрДлина(результат));
		лист.RemoveAt(индекс);
	КонецЦикла;

Это конечно не совсем асинхронное программирование, но все же лучше чем отдельно для каждого запроса вызывать синхронный метод.

Но нужно делать асинхронный вызов. Для этого создал простенький класс.

public class ��синхронныйВыполнитель
    {// Данные связанные с задачей, что бы понять, что к чему при получении события
        public object ДанныеДляЗадача;
      // Сама задача
        public Task Задача;
     // Имя метода 1С обрабатывающего окончание задачи.
        public String ИмяМетода;
     
        public АсинхронныйВыполнитель(Task Задача, String ИмяМетода, Object ДанныеДляЗадача)
        {
            this.Задача = Задача;
            this.ДанныеДляЗадача = ДанныеДляЗадача;
            this.ИмяМетода = ИмяМетода;
            Задача.ContinueWith((t) =>
            {
                var AW = new AutoWrap(this);
                AutoWrap.ВызватьВнешнееСобытие1С("АсинхронныйВыполнитель", ИмяМетода, AW.ПолучитьСсылку());
            });
        }
    }

А на стороне 1С:

Функция ПолучитьДанныеДляЗадачи(адрес,Номер)
	
	объект=ъНовый(ExpandoObject.ПолучитьСсылку());
	объект.Адрес=адрес;
	объект.Номер=Номер;
	возврат объект;
	
КонецФункции // ПолучитьДанныеДляЗадачи()

Процедура ТестАсинхронногоВыполнителяНажатие(Элемент)
		
	Клиент = ъ(Врап.Новый(HttpClient.ПолучитьСсылку(),handler.ПолучитьСсылку()));
	
	лист=ъНовый("System.Collections.Generic.List`1[System.Threading.Tasks.Task]");
	сч=0;
	Для каждого стр из ПолучитьСписокURL() Цикл
          // Получаем задачу
		Задача=ъ(Клиент.GetStringAsync(стр));
        // Получаем данные привязанные к данной задаче
		объект=ПолучитьДанныеДляЗадачи(стр,сч);
	//public static void ВыполнитьЗадачу(System.Threading.Tasks.Task Задача, String ИмяМетода, Object ДанныеДляЗадача)
              
		Врап.ВыполнитьЗадачу(Задача.ПолучитьСсылку(),"ПолученаСтраница",объект.ПолучитьСсылку());
		сч=сч+1;
		
	КонецЦикла;
	
	// Добавим тест на ошибку
	
	Тестовый=ъТип("TestDllForCoreClr.Тестовый","TestDllForCoreClr");
	Тест=ъ(Врап.Новый(Тестовый.ПолучитьСсылку()," Свойство из Конструктора"));
        Thread=ъТип("System.Threading.Thread");
	
	// При передаче 2 вызывается ошибка
	Задача=ъ(Тест.ЗадачаСОшибкойAsync(2));
	объект=ПолучитьДанныеДляЗадачи("ЗадачаСОшибкойAsync",2);
	Врап.ВыполнитьЗадачу(Задача.ПолучитьСсылку(),"ПолученаСтраница",объект.ПолучитьСсылку());

    Задача2=ъ(Тест.ЗадачаСОшибкойAsync(0));
	объект=ПолучитьДанныеДляЗадачи("ЗадачаСОшибкойAsync",0);
	Врап.ВыполнитьЗадачу(Задача2.ПолучитьСсылку(),"ПолученаСтраница",объект.ПолучитьСсылку());

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

Процедура   ПолученаСтраница(знач данные)
	
	Задача=ъ(данные.Задача);
	ДанныеДляЗадача=ъ(данные.ДанныеДляЗадача);
	Сообщить("Адрес="+ДанныеДляЗадача.Адрес);
	Сообщить("Номер="+ДанныеДляЗадача.Номер);

       // При возникновении ошибки при выполнении задачи
      // IsFaulted будет истина, а в Exception будет ошибка
	Если (Задача.IsFaulted) Тогда  // Ошибка выполнения
		    ошибка=Задача.Exception;
		    Сообщить("Ошибка "+Врап.ВСтроку(ошибка));
		//  Если сделать как ниже 1С хочет присвоить Задача.Exception новое значение
		//  Даже если оно не было изменено
                // Так как считает, что параметр передан по ссылке
		// Сообщить("Ошибка "+Врап.ВСтроку(Задача.Exception));
	    	   возврат;
	КонецЕсли;
		
	результат=Задача.Result;
	Сообщить(СтрДлина(результат));
КонецПроцедуры	

Процедура ВнешнееСобытие(Источник, Событие, Данные)
	// Вставить содержимое обработчика.
	
	Сообщить("Источник="+Источник);
	Сообщить("Событие="+Событие);
	Сообщить("Данные="+Данные);
	
	Если Источник="АсинхронныйВыполнитель" Тогда
		Данные=ъ(Данные);
		Выполнить(Событие+"(Данные)");
	КонецЕсли; 
КонецПроцедуры

Немного поясню по коду.

Так как в Native ВК нельзя использовать ДобавитьОбработчик то сделаем его эмуляцию передав в АсинхронныйВыполнитель имя метода, который нужно вызвать в 1С

Врап.ВыполнитьЗадачу(Задача.ПолучитьСсылку(),"ПолученаСтраница",объект.ПолучитьСсылку());

Который будет вызываться при срабатывании внешнего события.

        Если Источник="АсинхронныйВыполнитель" Тогда
		Данные=ъ(Данные);
		Выполнить(Событие+"(ПолученаСтраница)");
	КонецЕсли;

В данном в переменной Событие хранится ПолученаСтраница и будет вызван метод

ПолученаСтраница(ПолученаСтраница)

Теперь про использование Внешнего события в .Net сборке

Для этого нужно определить поле

 public Action<string, string, string> ВнешнееСобытие1С;

И установить его из 1С.

Тестовый=ъТип("TestDllForCoreClr.Тестовый, TestDllForCoreClr, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
	Тест=ъ(Врап.Новый(Тестовый.ПолучитьСсылку()," Свойство из Конструктора"));
	
	Делегат=Ъ(Врап.ПолучитьДелегатВнешнегоСобытия1C());
	Тест.ВнешнееСобытие1С=Делегат.ПолучитьСсылку();
	Тест.TestВнешнегоСобытия();

Внутри .Net класса вызвать метод

this?.ВнешнееСобытие1С("Тестовый", "ТестовоеСообщение", значение);

При этом в 1С вызовется процедура

Процедура ВнешнееСобытие(Источник, Событие, Данные)
	Сообщить("Источник="+Источник);
	Сообщить("Событие="+Событие);
	Сообщить("Данные="+Данные);
КонецПроцедуры


Я постарался максимально приблизить синтаксис C# в 1С. И по мне, так даже в таком виде проще писать ВК на C#, чем использовать Native API на C++. При этом можно интегрировать использование .Net классов в 1С. Добавляя синонимы можно писать все на кириллице. Можно добавить поддержку итераторов итд.

Сейчас на Windows много всяких ActiveX, кроме того не сложно и самим написать COM компонент на любом языке.
Но это не кроссплатформенно.

Используя .Net Core и данную обертку над объектами .Net в 1С можно значительно расширить возможности 1С используя огромное количество библиотек и классов в них находящихся. И сосредоточиться на разработку языка, наконец добавив замыкания, Linq, указание типа для intellisense (по аналогии с TypeScript). Разбиение модальных диалогов по аналогии с yeld и await в C#. А так же аналоги await для серверных вызовов с замыканиями.

Я понимаю, что данная разработка мало кому интересна. Но мне было интересно её разрабатывать. Кроме того будет интересна кто пробует .Net Core и использут Reflection

Примеры и исходники можно скачать Здесь