Страницы

Поиск по вопросам

пятница, 24 января 2020 г.

Использование в TypeScript классов .Net

#javascript #cpp #net #typescript #ecmascript_6


Есть идея иметь доступ из TypeScript к  методам и свойствам классов .Net.

У меня есть опыт вызова методов .Net объектов из натива https://habrahabr.ru/users/serginio1/topics/

И в частности Кроссплатформенное использование классов .Net из неуправляемого кода.
Или аналог IDispatch на Linux
   

Есть идея вызвать через Native Client Messaging System  

Там мы имеем взаимодействие JavaScript и натива через сообщения

В JavaScript мы можем подписаться на события

function handleMessage(message) {
  // In the example, we simply log the data that's received in the message.
  var logEl = document.getElementById('log');
  logEl.textContent += message.data;
}


И отправлять сообщения

var dictionary = {
  key:guid,
  MethodName: name,
  param_array: args
}
nacl_module.postMessage(dictionary);


На стороне натива

Можно принмать сообщения

virtual void HandleMessage(const pp::Var& var) {
  if (var.is_dictionary()) {
    pp::VarDictionary dictionary(var);
    // Use the dictionary
    pp::VarArray keys = dictionary.GetKeys();
    // ...
  } else {
    // ...
  }
}


Так и отправлять

pp::VarDictionary dictionary;
dictionary.Set(pp::Var("command"), pp::Var(next_command));
dictionary.Set(pp::Var("param_int"), pp::Var(123));
pp::VarArray an_array;
an_array.Set(0, pp::Var("string0"));
an_array.Set(1, pp::Var("string1"))
dictionary.Set(pp::Var("param_array"), an_array);
PostMessage(dictionary);


Все это можно сделать через Proxy 

class NetWrapper{

    public currentCount: any;

    public static dictionary = {};

    public proxy: any;

    public static wm = new WeakMap(); // Слабые ссылки на объекты
    public static refArray = new Array(); // ссылки на .Net объекты   
    constructor(private netRef:int) { this.SetProxy(); }


     private GetPromise(name: PropertyKey,args)
    {

        let key = Guid.newGuid();
        let promise = new Promise((resolve, reject) => {
            let item = new Item(resolve, args, name);
            this.dictionary[key] = item;

           var dictionary = {
           netRef:netRef,
           key:key,
           MethodName: name,
           param_array: args
         }
          nacl_module.postMessage(dictionary);
        });


        return promise;
    }


    private SetProxy(): void {

        let self=this;
        this.proxy = new Proxy({}, {

            get: function(rcvr: any, name: PropertyKey)
            {

               // Проблемы с определением, что свойство возвращает ссылку на метод
               // поэтому будем вызвать все как методы
               // if (этоСвойство)
               //     return self.GetPromise(name, []);

               return (...args) => {
                   return self.GetPromise(name,args)

                };


            }


        });
    }




// Пример вызова метода .Net

function handleMessage(message) {
  // In the example, we simply log the data that's received in the message.
  let data=message.data;
  let result=data.result;
  let item = this.dictionary[data.key];

  delete this.dictionary[key];

  if (data.resultIsObject)
   {

    let ref=result;
    result=new NetWrapper(ref);
    refArray.push(ref);
    wm.set(result,ref);
  }

  item.resolve(result);

}


Так как в в JavaScript нет финализаторов, то можно использовать WeakMap 

То есть можно было бы выгрузить значения из wm и сравнить их с текущим массивом ссылок
refArray. Если в WeakMap ссылок нет значит можно освободить ссылки и на стороне .Net

Но вроде как 


  Из-за того, что ссылки являются слабыми, ключи WeakMap не перечисляемы
  (то есть нет метода, который возвращает список ключей). Иначе список
  бы зависел от состояния сбора мусора, представляя индетерминизм. Если
  Вы хотите иметь список ключей, Вам следует поддерживать его
  самостоятельно.


Использование такое

  let HttpClient=await NetWrap.GetType("System.Net.Http.HttpClient","System.Net.Http.dll");
     let HttpClientHandler = await NetWrap.GetType("System.Net.Http.HttpClientHandler","System.Net.Http.dll");

    let client=await NetWrap.new(HttpClient);
    let responst= await (await client.GetStringAsync("https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx")).Result();
 //Result вызываем как функцию


Можно для асинхронных методов result внутри Net сделать асинхронным

Буду рад любым советам. И может это никому и не нужно и не стоит вообще писать в стол?

Правда нашел ссылку на возможность финализатора https://www.npmjs.com/package/finalize

var finalize = require('finalize');
 
var obj = { x: 1337 };
finalize(obj, function () {
  console.log(this.x); // this will print '1337' 
});
global.gc();
// nothing will happen, var obj above holds obj alive 
obj = null;
global.gc();
// the previous line should trigger the callback above 


Кроме того для интегации мне посрветовали cef / JavaScriptIntegration 

Можно и без асинхронности  вызова обычных методов обойтись.

При этом можно зарегистрировать различные обработчики для асинхронных методов, для
событий

В итоге можно вызывать асинхронные методы например добавив кллючевое слово async,
а для свойств можно использовать @ в начале свойства

let url= "https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx");
let response= await client.async.GetStringAsync(url);
let response= client.GetStringAsync(url).@Result;

    


Ответы

Ответ 1



Сделал и работает на Angular 2 и TypeScript let Net = NetObject.NetWrapper; let del = NetObject.FlagDeleteObject; //let SB = Net.Новый("System.Text.StringBuilder"); let StringBuilder = Net.Тип("System.Text.StringBuilder"); let SB = new StringBuilder(); this.AddComment("SB", SB); var res = SB.Append("Первая строка"); res(del); var ToStr = SB.ToString(); this.AddComment("Tostring=", ToStr); SB.Capacity=40; res = SB._Capacity; this.AddComment("_Capacity=", res); SB(del); let Тестовый = Net.Тип("TestDllForCoreClr.Тестовый", "TestDllForCoreClr"); var TO = new Тестовый("Свойство из Конструктора"); var resAsync = await TO.async.GetStringAsync(); this.ResultExecute.push(new ResTest("GetStringAsync", resAsync)); res = TO.ДженерикМетод(1, 2, 5); this.AddComment("ДженерикМетод с выводом типов ", res); let Int32 = Net.GetType("System.Int32"); res = TO.ДженерикМетод([Int32, Int32], 1, 2, 5); this.AddComment("ДженерикМетод с аргeментами типов ", res); var Dictionary2 = Net.GetType("System.Collections.Generic.Dictionary`2", "System.Collections"); var DyctionaryIS = Net.GetGenericType(Dictionary2, "System.Int32", "System.String"); var D = new DyctionaryIS(); res = TO.ДженерикМетод2(D, 99, "Hello"); this.AddComment("ДженерикМетод2 с выводом типов ", res); res = TO.ДженерикМетод2([Int32, "System.String"],D, 99, "Hello"); this.AddComment("ДженерикМетод2 с аргументами ", res); var task = TO.GetStringAsync(); res = await Net.async.ReturnParam(task); this.AddComment("выполнение полученной задачи асинхронно ", res); var array = Net.GetNetArray(1, "Привет", 4.4); for (let item of array) this.AddComment("Элемент ", item); var EO = TO.ПолучитьExpandoObject(); this.AddComment("Свойство ExpandoObject Имя ",EO._Имя); this.AddComment("Свойство ExpandoObject Число ", EO._Число); var делегат = EO._ВСтроку; this.AddComment("Результат вызова делегата Встроку ", делегат()); this.AddComment("Результат вызова как Метода ", EO.ВСтроку()); NetObject.DeleteNetObjets(Int32, task, D, DyctionaryIS, Dictionary2, TO, Тестовый, StringBuilder, array, EO, делегат); this.AddComment("Количество элементов в хранилище ", Net.КоличествоЭлементовВХранилище()); this.AddComment("Первый удаленный ", Net.FirstDeleted()); Отличие от C# это Для получения свойства нужно добавить "_" res = SB._Capacity; Для вызова асинхронного метода нужно добавить ключевое слово async var resAsync = await TO.async.GetStringAsync(); Для вызова дженерик метода, если нельзя вывести типы по параметрам то аргументы указываем в массиве res = TO.ДженерикМетод2([Int32, "System.String"],D, 99, "Hello"); Поддержку событий и передачу объектов JS добавлю позже. Буду рад любым предложениям и критике.   Какие примеры лучше дать для статьи? Выложил в итоге статью с примерами CEF, ES6, Angular 2, TypeScript использование классов .Net Core для расширения возможностей И еще CEF, Angular 2 использование событий классов .Net Core И еще CEF, ES6, Angular 2, WebPack 2 .Net Core десктопное приложение без серверной части

Ответ 2



Кроме того на RSDN мне посоветовали CEF удобное C++ API еще ссылка cef / JavaScriptIntegration Можно и без асинхронности вызова обычных методов обойтись. При этом можно зарегистрировать различные обработчики для асинхронных методов, для событий В итоге можно вызывать асинхронные методы например добавив кллючевое слово async, а для свойств можно использовать @ в начале свойства Кроме того можно переопределить new let HttpClient= NetWrap.GetType("System.Net.Http.HttpClient","System.Net.Http.dll"); let HttpClientHandler = NetWrap.GetType("System.Net.Http.HttpClientHandler","System.Net.Http.dll"); let client= new HttpClient(HttpClientHandler); let url= "https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx"); let response= await client.async.GetStringAsync(url); let response= client.GetStringAsync(url).@Result; для ref параметров можно использовать класс обертку class RefParam{ isRefparam=true; constructor(public Value:any); } Кроме того можно реализовать enumerate для доступа через for(let prop in proxy) Если кому интересно, то выложил статью CEF,Es6,Angular 2,TypeScript использование классов .Net Core для расширения возможностей

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

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