using System;
using System.Collections.Generic;
using System.Reflection;
namespace CoreClrDLL
{
public class Program
{
public static object ExecuteMethod(object objOrig, string MethodName, params object[] argsOrig)
{
object res = null;
Type T = objOrig.GetType();
var list = new List<Type>();
foreach (var obj in argsOrig)
list.Add(obj.GetType());
var Method = T.GetMethod(MethodName, list.ToArray());
res = Method.Invoke(objOrig, argsOrig);
return res;
}
public static int TestFunction(int i)
{
var rn = new Random(i);
// int res = rn.Next(10000);int res = (int)ExecuteMethod(rn, "Next", 10000);
return res;
}
}
}
Здравствуйте, Serginio1, Вы писали:
S>Нет InvokeMember придется вручную искать перегруженную функцию.
S>Вобщем оболочку можно сделать
InvokeMember брал на себя поиск нужного метода и передачу параметров params.
И соответственно встал вопрос как искать подходящий метод.
1. Когда один из параметров null
Каков приоритет типов?
2. Кода есть params
Сначала идут методы с большим количеством параметров?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> InvokeMember брал на себя поиск нужного метода и передачу параметров params. S>И соответственно встал вопрос как искать подходящий метод.
Для начала лучше перетащить разруливание перегрузок в managed-код. Дальше проще и зависит от задачи.
Известны только значения? Пишем вызов любого метода через dynamic, с помошью декомпилятора смотрим что за код генерится под капотом, повторяем вручную. Ключевые слова для поиска — CallSite<T>, CallSiteBinder.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>> InvokeMember брал на себя поиск нужного метода и передачу параметров params. S>>И соответственно встал вопрос как искать подходящий метод.
S>Для начала лучше перетащить разруливание перегрузок в managed-код. Дальше проще и зависит от задачи.
S>Подобрать перегрузку, зная типы аргументов? type.GetMethod("name", bindingFlags, argTypes) или как-то так.
S>Известны только значения? Пишем вызов любого метода через dynamic, с помошью декомпилятора смотрим что за код генерится под капотом, повторяем вручную. Ключевые слова для поиска — CallSite<T>, CallSiteBinder.
S>Первое попавшееся: https://habrahabr.ru/post/144330/
Это все прекрасно работает в Win через COM и InvokeMember. Но есть желание перенести это все на Линукс.
Соответственно я не знаю, что и как будет вызываться, но динамически я должен найти самый подходящий перегруженный метод.
S> Я хочу сделать по аналогии с Использование сборок .NET в 1С 7.x b 8.x.
А тут не имеет значения, что вы хотите. Важно только то, что поддерживается, т.е. C-style ABIs. Зачатки COM Interop есть, но только под win.
Нужно что-то более изощрённое — придётся изобретать магию самому, что требует досконального знания как нативной части, так и кишков маршаллинга CoreCLR. Я, к примеру, за это не возьмусь, т.к. только на поверхностное изучение минимум пару недель придётся потратить.
S> То есть использование любых сборок из Натива.
В общем случае нереально. Не, если ограничиться структурами / делегатами и следить за временем жизни ссылок, то что-то может и получиться, но на "любых сборок" я бы не рассчитывал. Вам точно не достаточно того, что есть в оф.справке, секция "Invoking managed code from unmanaged code"?
Если что, даже менее амбициозные замашки на c++ выглядят как-то так.
S> Это все прекрасно работает в Win через COM и InvokeMember. Но есть желание перенести это все на Линукс.
Нельзя просто так взять и перенести COM на платформу, которая его не поддерживает. Ваш кэп
S>При вызове Метод(1,null) какой метод выбрать?
Простой способ: AmbigiousMatchException
Сложный способ — подрубаем DLR, как советовал выше
S>То в Core все через расширения
Core как такового нет. Есть RC, которое, как ВНЕЗАПНО выяснилось, несовместимо с 99% существующего кода и невнятные обещания binary compatibility для основных классов BCL, включая reflection.
Я бы не заморачивался с как минимум до следующего релиза. Если конечно нет желания оседлать хайп и снять все сливки Риски соответствующие.
Здравствуйте, Sinix, Вы писали:
S> Здравствуйте, Serginio1, Вы писали:
S>> Я хочу сделать по аналогии с Использование сборок .NET в 1С 7.x b 8.x. S>А тут не имеет значения, что вы хотите. Важно только то, что поддерживается, т.е. C-style ABIs. Зачатки COM Interop есть, но только под win. S>Нужно что-то более изощрённое — придётся изобретать магию самому, что требует досконального знания как нативной части, так и кишков маршаллинга CoreCLR. Я, к примеру, за это не возьмусь, т.к. только на поверхностное изучение минимум пару недель придётся потратить.
S>> То есть использование любых сборок из Натива. S>В общем случае нереально. Не, если ограничиться структурами / делегатами и следить за временем жизни ссылок, то что-то может и получиться, но на "любых сборок" я бы не рассчитывал. Вам точно не достаточно того, что есть в оф.справке, секция "Invoking managed code from unmanaged code"?
Реально. Кратко. Объекты хранятся в массивах. Передаются индексы в массивах. На стороне 1С есть метод
bool CAddInNative::CallAsFunc(const long lMethodNum,
tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray)
{
return false;
}
Через IntPtr зная структуры я могу распаковать параметры (Marshal)в том числе и индексы на Объекты. А память для строк byte[] я могу на стороне .Net получив ссылку на метод.
Могу просто все запаковывать в масив.
Меня сейчас просто волнуют приоритеты перегруженных методов. Но могу не заморачиваться пока и выбирать подходящий метод
S>Если что, даже менее амбициозные замашки на c++ выглядят как-то так.
S>> Это все прекрасно работает в Win через COM и InvokeMember. Но есть желание перенести это все на Линукс. S>Нельзя просто так взять и перенести COM на платформу, которая его не поддерживает. Ваш кэп
Был такой компонет TSocketConnection в Delphi. Суть его в том, что это была замена DCOM. Дам используя IDispatch данные упаковывались в массив. Ссылки на объекты на стороне сервера упаковывались в Idispatch и маршалились обратно. Все это реализуема на уровне собственного маршалинга.
S>>При вызове Метод(1,null) какой метод выбрать? S>Простой способ: AmbigiousMatchException S>Сложный способ — подрубаем DLR, как советовал выше
DLR не подходит. Я не знаю заранее, что вызовется. В DLR уже известна сигнатура.
S>>То в Core все через расширения S>Core как такового нет. Есть RC, которое, как ВНЕЗАПНО выяснилось, несовместимо с 99% существующего кода и невнятные обещания binary compatibility для основных классов BCL, включая reflection.
Ну Method.Invoke(); и
Type T = typeof(string);
var Method = T.GetMethod("Format",new Type[]{ T, typeof(Object[])});
Работают. S>Я бы не заморачивался с как минимум до следующего релиза. Если конечно нет желания оседлать хайп и снять все сливки Риски соответствующие.
Ну мне еще C++ нужно изучить, а заодно напишу аналог InvokeMember
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>>> То есть использование любых сборок из Натива. S>>В общем случае нереально. S> Реально. Кратко. Объекты хранятся в массивах. Передаются индексы в массивах. На стороне 1С есть метод
Оно будет работать или для вызовов managed->native, или для случаев, когда объекты живут не дольше, чем время вызова native->managed. Иначе получаем или утечку объектов на managed-стороне, или порчу памяти из-за пожраного GC объекта, или адскую магию с рефкаунтингом (по, сути, переизобретение IUnknown).
Довольно существенное ограничение.
Если устраивает — всё сводится к получить на managed-стороне массив объектов-параметров + тип + имя метода. Дальше всё как в первом ответе написал, второй вариант.
S> DLR не подходит. Я не знаю заранее, что вызовется. В DLR уже известна сигнатура.
Вообще-то неизвестна, в рантайме определяется. Достаточно только набора значений.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>>>> То есть использование любых сборок из Натива. S>>>В общем случае нереально. S>> Реально. Кратко. Объекты хранятся в массивах. Передаются индексы в массивах. На стороне 1С есть метод
S>Оно будет работать или для вызовов managed->native, или для случаев, когда объекты живут не дольше, чем время вызова native->managed. Иначе получаем или утечку объектов на managed-стороне, или порчу памяти из-за пожраного GC объекта, или адскую магию с рефкаунтингом (по, сути, переизобретение IUnknown).
Не читаешь ты. Прежде чем отправить в натив объект сохраняется в статическом массиве массиве. Жить он будет пока его из массива не удалят.
На стороне 1С есть подсчет ссылок и Done() при разрушении объекта, которое я могу ипользовать для удаления из массива.
Кроме того можно освобождать все ссылки при разрушении домена
pCLRRuntimeHost->UnloadAppDomain(domainId, true);
// Stop the runtime host
pCLRRuntimeHost->Stop();
S>Довольно существенное ограничение.
S>Если устраивает — всё сводится к получить на managed-стороне массив объектов-параметров + тип + имя метода. Дальше всё как в первом ответе написал, второй вариант.
S>> DLR не подходит. Я не знаю заранее, что вызовется. В DLR уже известна сигнатура. S>Вообще-то неизвестна, в рантайме определяется. Достаточно только набора значений.
DLR то как раз статический. Но он мне все равно нужен для использования DynamicObject
Кстати попробовал на стороне Манагед
public static int TestFunctionIntPtr(IntPtr i)
{
int res = Marshal.ReadInt32(i);
return res;
}
И вызов
typedef int (STDMETHODCALLTYPE *ManagedMethodIntPtr)(int*);
ManagedMethodIntPtr pTestFunctionIntPtr;
//TestFunctionIntPtr
hr = CreateDelegate2(pCLRRuntimeHost, domainId, L"CoreClrDLL", L"CoreClrDLL.Program", L"TestFunctionIntPtr", (INT_PTR*)&pTestFunctionIntPtr);
if (FAILED(hr))
{
printf_s("Failed to create a delegate to the managed entry point: (%d).\n", hr);
}
else
{
cout << "Press Key";
cin.get();
int i = 555;
printf_s("result method pTestFunctionIntPtr(555) : (%d).\n", pTestFunctionIntPtr(&i));
}
Marshal такой же как и во взрослом. А значит могу ползать по памяти как хочу.
и солнце б утром не вставало, когда бы не было меня
S>> DLR не подходит. Я не знаю заранее, что вызовется. В DLR уже известна сигнатура. S>Вообще-то неизвестна, в рантайме определяется. Достаточно только набора значений.
Ну самом деле в DLR строится дерево и компилится. Это нормально, когда известны методы, сигнатура они известны на этапе компиляции.
А вот в моем случае вообще ничего неизвестно.
Но это не большая беда, так как я могу получить используемые типы. Просто нужны правила для приоритетов.
То есть методы я могу отсортировать по признаку есть params или нет, ну и по количеству параметров.
Сначала отбираются без params, если не находятся, то выбираются от большего к меньшему с params.
А, что касается null, то случайным образом из доступных ссылочных типов или Nullable
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали: S> Не читаешь ты. Прежде чем отправить в натив объект сохраняется в статическом массиве массиве. Жить он будет пока его из массива не удалят.
Ну, т.е. как и говорил, получаем или утечку объектов на managed-стороне, или адскую магию с рефкаунтингом (по, сути, переизобретение IUnknown).
Для сложных графов с изменяемыми свойствами-объектами тесты как минимум надо сделать S>>Вообще-то неизвестна, в рантайме определяется. Достаточно только набора значений. S> DLR то как раз статический. Но он мне все равно нужен для использования DynamicObject
Вот народ я с вас фигею. Вам дают карту с сокровищами, а вы требуете чтоб вас экспрессом минуя все три тома приключений доставили прямо в термал спа "Золотое кольцо" (магнитик на холодильник с Балрогом в подарок). Где ваша это... мазохизм? Стремление усложнить жизнь? Граблефилия? А, авантюризм, во!
Здравствуйте, Sinix, Вы писали: S>Здравствуйте, Serginio1, Вы писали: S>> Не читаешь ты. Прежде чем отправить в натив объект сохраняется в статическом массиве массиве. Жить он будет пока его из массива не удалят. S>Ну, т.е. как и говорил, получаем или утечку объектов на managed-стороне, или адскую магию с рефкаунтингом (по, сути, переизобретение IUnknown). S>Для сложных графов с изменяемыми свойствами-объектами тесты как минимум надо сделать
Опять не читаешь. На стороне 1С есть подсчет ссылок и Done при разрушении.
Кроме того могу выгрузить домен. S>>>Вообще-то неизвестна, в рантайме определяется. Достаточно только набора значений. S>> DLR то как раз статический. Но он мне все равно нужен для использования DynamicObject S>Вот народ я с вас фигею. Вам дают карту с сокровищами, а вы требуете чтоб вас экспрессом минуя все три тома приключений доставили прямо в термал спа "Золотое кольцо" (магнитик на холодильник с Балрогом в подарок). Где ваша это... мазохизм? Стремление усложнить жизнь? Граблефилия? А, авантюризм, во! S>Держите, скучный вы человек: S>
S>Как допилить до вызова произвольного метода — сами-сами. Иначе вообще никакого удовольствия не будет. S>
P.S.
Спасибо! Веселый Вы наш. Но возникают вопросы.
Я так понимаю, что можно создать Кучу CallSite<Action<CallSite, Type, object, object>>
По количеству аргументов и использовать их?
И получается для каждого вызова я должен создавать свой callSite по имени метода, типу и количеству агрументов.
Сейчас проверю кстати код на CoreClr.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>1. CallSite под определенную сигнатуру (CallSite<Action<CallSite, Type, object, object>> )
Угу. Но нагенерить конечное количество не проблема как бы, достаточно прошвырнуться по GetMethods().
S>2. Как определить с params (удобно передавать без массива)
Не, ну до такой степени лениться — это уже перебор Первый вызов в примере.
S>3. Каково время на компиляцию если для каждого вызова нужно создавать CallSite?
Хитрый план:
1. Взять штуку, которая используется под капотом IronPython/IronRuby/прочих динамических языков под CLR.
2. Подозревать, что оно может тормозить.
Не для каждого, а для первого. CallSite кэширует сгенеренные делегаты.
S> Пока это мало чем отличается от T.GetMethod(имяМетода,Type[] типы);
Не вопрос, как сделаете корректное разруливание перегрузок по значениям аргументов в GetMethod() — так сразу и приходите.
P.S. И чистите при ответе оверквотинг Глаза же вылазят.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>>1. CallSite под определенную сигнатуру (CallSite<Action<CallSite, Type, object, object>> ) S>Угу. Но нагенерить конечное количество не проблема как бы, достаточно прошвырнуться по GetMethods().
У меня обертка не для одного типа, а для вех возможных типов, о которых я не знаю на этапе компиляции.
В DLR уже заранее известно и имя метода и количество параметров.
Для моего подхода это не совсем удобно, хотя конечно можно и поизвращаться.
Но по моему проще самому написать поиск нужного метода. Это не сложно. Логика приоритеты мне понятны.
Кстати возможно, что при вызове GetMethods они идут уже в приоритетно порядке. Посмотрю.
S>>2. Как определить с params (удобно передавать без массива)
S>Не, ну до такой степени лениться — это уже перебор Первый вызов в примере.
Прошу прощения. Я уже подправил ответ.
S>>3. Каково время на компиляцию если для каждого вызова нужно создавать CallSite? S>Хитрый план: S>1. Взять штуку, которая используется под капотом IronPython/IronRuby/прочих динамических языков под CLR. S>2. Подозревать, что оно может тормозить. S>
S>Не для каждого, а для первого. CallSite кэширует сгенеренные делегаты.
Ну у меня то может быть всего один раз.
S>> Пока это мало чем отличается от T.GetMethod(имяМетода,Type[] типы); S>Не вопрос, как сделаете корректное разруливание перегрузок по значениям аргументов в GetMethod() — так сразу и приходите.
Да там не так и сложно. Если GetMethods() выдает по приоритету.
S>P.S. И чистите при ответе оверквотинг Глаза же вылазят.
Ок.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>>Угу. Но нагенерить конечное количество не проблема как бы, достаточно прошвырнуться по GetMethods(). S> У меня обертка не для одного типа, а для вех возможных типов, о которых я не знаю на этапе компиляции.
В рантайме нагенерить. Ну блин, не заставляйте меня совсем всё разжёвывать, так неинтересно.
S>В DLR уже заранее известно и имя метода и количество параметров. S> Для моего подхода это не совсем удобно, хотя конечно можно и поизвращаться. S>Но по моему проще самому написать поиск нужного метода. Это не сложно. Логика приоритеты мне понятны.
Магия с корректным разруливанием перегрузок включая вывод генерик-параметров и implicit conversions — одна из сложнейших частей шарпа.
Оптимизм это конечно хорошо, но только при условии, что человек ориентируется в матчасти.
Иначе получается что-то в духе "хочу сделать свою СУБД. Логика и приоритеты понятны, так что проблем не будет."
Оно с одной стороны забавно, с другой — представляешь, сколько времени будет убито впустую чисто из-за нежелания разобраться в вопросе и уже не смешно.
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>>>Угу. Но нагенерить конечное количество не проблема как бы, достаточно прошвырнуться по GetMethods(). S>> У меня обертка не для одного типа, а для вех возможных типов, о которых я не знаю на этапе компиляции. S>В рантайме нагенерить. Ну блин, не заставляйте меня совсем всё разжёвывать, так неинтересно.
Это я понимаю. Вопрос что выгоднее сделать универсальный поиск метода или генерить в рантайме калсайты.
S>>В DLR уже заранее известно и имя метода и количество параметров. S>> Для моего подхода это не совсем удобно, хотя конечно можно и поизвращаться. S>>Но по моему проще самому написать поиск нужного метода. Это не сложно. Логика приоритеты мне понятны.
S>Магия с корректным разруливанием перегрузок включая вывод генерик-параметров и implicit conversions — одна из сложнейших частей шарпа.
Согласен. Но она существует.
S>Оптимизм это конечно хорошо, но только при условии, что человек ориентируется в матчасти. S>Иначе получается что-то в духе "хочу сделать свою СУБД. Логика и приоритеты понятны, так что проблем не будет." S>Оно с одной стороны забавно, с другой — представляешь, сколько времени будет убито впустую чисто из-за нежелания разобраться в вопросе и уже не смешно.
Но и твое предложение не совсем удобно. Практический на каждый вызов я должен создавать привязку.
Хотя можно ограничится и 16 параметрами. Надо посмотреть на производительность и для каждого типа кэшировать методы по имени метода и количеству параметров.
Спасибо!
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>>>Угу. Но нагенерить конечное количество не проблема как бы, достаточно прошвырнуться по GetMethods(). S>> У меня обертка не для одного типа, а для вех возможных типов, о которых я не знаю на этапе компиляции. S>В рантайме нагенерить. Ну блин, не заставляйте меня совсем всё разжёвывать, так неинтересно.
Здравствуйте, Serginio1, Вы писали:
S> Это я понимаю. Вопрос что выгоднее сделать универсальный поиск метода или генерить в рантайме калсайты.
Вопрос из серии "сделать универсальный транслятор sql-запросов или просто подключить EF?"
S>>Магия с корректным разруливанием перегрузок включая вывод генерик-параметров и implicit conversions — одна из сложнейших частей шарпа. S> Согласен. Но она существует.
Это не значит, что её легко повторить
S> Но и твое предложение не совсем удобно. Практический на каждый вызов я должен создавать привязку.
"И конфеты за меня есть будете? — Ага!". Ну и далее по тексту. Раз сами просите — вот вам: убийца -- садовник. Эхх, такую интригу убили...