public class MyComparer : IComparer<Type>
{
public int Compare(Type TypeA, Type TypeB)
{
if (TypeA.IsAssignableFrom(TypeB)) return 1;
if (TypeB.IsAssignableFrom(TypeA)) return -1;
if (TypeA.IsByRef) return -1;
if (TypeB.IsByRef) return 1;
return 0;
}
}
Сортировка типов получается такая.
var Comp = new MyComparer();
var tt = (new Type[] { typeof(int), typeof(int).MakeByRefType(), typeof(double), typeof(object), typeof(string) }).OrderBy(t=>t, Comp).ToArray();
var Method = typeof(DynamicCall).GetMethod("CallA", new Type[] { typeof(int).MakeByRefType(), typeof(double) });
object[] парам= new object[] { i,d};
res = Method.Invoke(null, парам);
Изменяет первый элемент массива.
Можно сортировать как 1000- уровень иерархии от Object
и солнце б утром не вставало, когда бы не было меня
Кстати решил посмотреть что выдает GetMethod с параметрами без сигнатуры
так вызов
typeof(DynamicCall).GetMethod("CallA", new Type[] { typeof(int), typeof(int) })
{Int32 CallA(Int32, Double)}
На
typeof(DynamicCall).GetMethod("CallA", new Type[] { typeof(int), typeof(string) })
ругается
А на
typeof(DynamicCall).GetMethod("CallA", new Type[] { typeof(object), typeof(string) })
все нормально.
Да уж.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sinix, Вы писали: S>Не вопрос, как сделаете корректное разруливание перегрузок по значениям аргументов в GetMethod() — так сразу и приходите.
Идея такая создаем класс для сравнения
namespace CoreClrDLL
{
public class ИнформацияОТипе: IComparable<ИнформацияОТипе>
{
public Type Тип;
bool IsByRef;
bool IsValue;
int УровеньИерархии;
bool IsNullable;
public ИнформацияОТипе(Type type)
{
var TI = type.GetTypeInfo();
IsByRef = TI.IsByRef;
if (IsByRef)
{
Тип = type.GetElementType();
TI = Тип.GetTypeInfo();
}
else
Тип = type;
IsValue = TI.IsValueType;
if (IsValue)
{
УровеньИерархии = 0;
if (TI.IsGenericType && TI.GetGenericTypeDefinition() == typeof(Nullable<>))
{
IsNullable = true;
Тип = TI.GenericTypeArguments[0];
}
}
else
УровеньИерархии = НайтиУровень(0, Тип);
}
static int НайтиУровень(int Уровень, Type type)
{
if (type == typeof(object))
return Уровень;
return НайтиУровень(Уровень + 1, type.GetTypeInfo().BaseType);
}
public int CompareTo(ИнформацияОТипе elem)
{
int res = -IsByRef.CompareTo(elem.IsByRef);
if (res != 0) return res;
if (Тип == elem.Тип)
return 0;
res = -IsValue.CompareTo(elem.IsValue);
if (res != 0) return res;
if (IsValue && elem.IsValue)
{
res = IsNullable.CompareTo(elem.IsNullable);
if (res != 0) return res;
}
res = -УровеньИерархии.CompareTo(elem.УровеньИерархии);
if (res != 0) return res;
return Тип.ToString().CompareTo(elem.Тип.ToString());
}
public bool Равняется(Type type)
{
if (type==null)
{
if (!IsValue)
return true;
if (IsNullable)
return true;
else
return false;
}
// или использовать IsInstanceOfTypeif (IsValue) return Тип == type;
return Тип.IsAssignableFrom(type);
}
}
public class ИнфoрмацияОМетоде<T> where T : MethodBase
{
public T Method;
public ИнформацияОТипе[] Параметры;
public int КоличествоПараметров;
public bool hasParams;
public Type TypeParams;
public int КоличествоПараметровПарамс;
public ИнформацияОТипе ИнформацияОТипеЭлемента;
public static Dictionary<Type, ИнформацияОТипе> ИнформацияПоТипу = new Dictionary<Type, ИнформацияОТипе>();
public static ИнформацияОТипе ПолучитьИнформациюОТипе(Type type)
{
ИнформацияОТипе ИТ = null;
if (!ИнформацияПоТипу.TryGetValue(type,out ИТ))
{
ИТ = new ИнформацияОТипе(type);
ИнформацияПоТипу[type] = ИТ;
}
return ИТ;
}
public ИнфoрмацияОМетоде(T MI)
{
Method = MI;
ParameterInfo[] parameters = Method.GetParameters();
hasParams = false;
КоличествоПараметров = parameters.Length;
if (КоличествоПараметров > 0)
{
hasParams = parameters[parameters.Length - 1].GetCustomAttributes(typeof(ParamArrayAttribute), false).GetEnumerator().MoveNext();
}
if (hasParams)
{
TypeParams = parameters[parameters.Length - 1].ParameterType.GetElementType();
ИнформацияОТипеЭлемента = ПолучитьИнформациюОТипе(TypeParams);
}
Параметры = new ИнформацияОТипе[КоличествоПараметров];
for(int i=0;i< parameters.Length;i++)
{
Параметры[i] = ПолучитьИнформациюОТипе(parameters[i].ParameterType);
}
}
public ИнфoрмацияОМетоде(ИнфoрмацияОМетоде<T> ИМ, int КолПарам)
{
Method = ИМ.Method;
КоличествоПараметров = КолПарам;
КоличествоПараметровПарамс = ИМ.КоличествоПараметров;
hasParams = true;
TypeParams = ИМ.TypeParams;
ИнформацияОТипеЭлемента = ИМ.ИнформацияОТипеЭлемента;
Параметры = new ИнформацияОТипе[КолПарам];
for (int i = 0; i < КоличествоПараметровПарамс - 1; i++)
{
Параметры[i] =ИМ.Параметры[i];
}
var ИОТ= ПолучитьИнформациюОТипе(ИМ.TypeParams);
for (int i = КоличествоПараметровПарамс - 1; i < КолПарам; i++)
{
Параметры[i] = ИОТ;
}
}
// Добавить парамс как обычный методpublic ИнфoрмацияОМетоде(ИнфoрмацияОМетоде<T> ИМ)
{
Method = ИМ.Method;
КоличествоПараметров = ИМ.КоличествоПараметров;
КоличествоПараметровПарамс = 0;
hasParams = false;
Параметры = ИМ.Параметры;
}
public bool Сравнить(Type[] параметры)
{
for (int i = 0; i < КоличествоПараметров ; i++)
{
if (!Параметры[i].Равняется(параметры[i]))
return false;
}
return true;
}
public bool СравнитьПарамс(Type[] параметры)
{
var ПоследнийПарам = КоличествоПараметров - 1;
if (параметры.Length < ПоследнийПарам)
return false;
for (int i = 0; i < ПоследнийПарам; i++)
{
if (!Параметры[i].Равняется(параметры[i]))
return false;
}
for (int i = ПоследнийПарам; i < параметры.Length; i++)
{
if ( !ИнформацияОТипеЭлемента.Равняется(параметры[i]))
return false;
}
return true;
}
public object ВыполнитьМетод(object Target, params object[] input)
{
if (!hasParams)
return Method.Invoke(Target, input);
int последняяПозиция = КоличествоПараметров - 1;
object[] realParams = new object[КоличествоПараметров];
for (int i = 0; i < последняяПозиция; i++)
realParams[i] = input[i];
Array массивПараметров = Array.CreateInstance(TypeParams, input.Length - последняяПозиция);
for (int i = 0; i < массивПараметров.Length; i++)
массивПараметров.SetValue(input[i + последняяПозиция], i);
realParams[последняяПозиция] = массивПараметров;
var res= Method.Invoke(Target, realParams);
массивПараметров = (Array)realParams[последняяПозиция];
for (int i = 0; i < массивПараметров.Length; i++)
input[i + последняяПозиция] = realParams.GetValue(i);
return res;
}
}
}
Тип для IsByRef узнаем через GetElementType();
var tint = typeof(int).MakeByRefType().GetElementType();
Для примера с CallA создаем массив по параметрам.
Для методов params разврачиваем params в массив параметров но нужного количества. В примере с
static public void CallA(params int[] args)
разворачиваем до
static public void CallA(int arg1,int arg1)
Если аргументы равны, то сравниваем сначала по params, а затем по количеству аргументов (сначала идут с большим аргументом)
То есть
static public void CallA(int arg1,params int[] args)
идет раньше, чем
static public void CallA(params int[] args)
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
Хе. А ведь таиким макаром можно добавить для каждого типа типы содержащие методы расширители и их использовать при поиске нужно сигнатуры.
Кроме того можно использовать дженерик методы тип которых можно определить по типу параметров.
Тогда можно писать почти одинаково как на C#
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, gnome, Вы писали:
G>Для начала попробуй http://bfy.tw/6Etw
Добрый полезный совет: сначала ознакомиться с вопросом, затем набрасывать. Порядок важен А то как в этот раз выйдет — в результатах поиска 0 ответов по теме.
Топикстартер знает, как вызвать coreCLR из натива (в стартовом посте ссылки были). Проблема в другом: он хочет аналог COM interop на платформе, которая его пока не поддерживает.
namespace CoreClrDLL
{
public class СравнительМетодов<T> : IComparer<ИнфoрмацияОМетоде<T>> where T : MethodBase
{
public int Compare(ИнфoрмацияОМетоде<T> A, ИнфoрмацияОМетоде<T> B)
{
int res = 0;
for (int i=0; i< A.Параметры.Count(); i++)
{
res = A.Параметры[i].CompareTo(B.Параметры[i]);
if (res != 0) return res;
}
res = A.hasParams.CompareTo(B.hasParams);
if (res != 0) return res;
res = -A.КоличествоПараметровПарамс.CompareTo(B.КоличествоПараметровПарамс);
if (res != 0) return res;
return A.Method.ToString().CompareTo(B.Method.ToString());
}
}
public class СравнительМетодовСпарамс<T> : IComparer<ИнфoрмацияОМетоде<T>> where T : MethodBase
{
public int Compare(ИнфoрмацияОМетоде<T> A, ИнфoрмацияОМетоде<T> B)
{
int res = 0;
res = -A.КоличествоПараметров.CompareTo(B.КоличествоПараметров);
if (res != 0) return res;
for (int i = 0; i < A.Параметры.Count() - 1; i++)
{
res = A.Параметры[i].CompareTo(B.Параметры[i]);
if (res != 0) return res;
}
res = A.hasParams.CompareTo(B.hasParams);
if (res != 0) return res;
return A.Method.ToString().CompareTo(B.Method.ToString());
}
}
public class ВсеМетодыПоИмени<T> where T : MethodBase
{
Dictionary<int, List<ИнфoрмацияОМетоде<T>>> ОбычныеМетоды=new Dictionary<int, List<ИнфoрмацияОМетоде<T>>>();
List<ИнфoрмацияОМетоде<T>> МетодыСParams=new List<ИнфoрмацияОМетоде<T>>();
void ДобавитьВСловарь(ИнфoрмацияОМетоде<T> им, int КоличествоПараметров)
{
List<ИнфoрмацияОМетоде <T>> СписокМетодов = null;
if (!ОбычныеМетоды.TryGetValue(КоличествоПараметров, out СписокМетодов))
{
СписокМетодов = new List<ИнфoрмацияОМетоде<T>>();
ОбычныеМетоды[КоличествоПараметров] = СписокМетодов;
}
СписокМетодов.Add(им);
}
void ДобавитПарамсВСписок(KeyValuePair<int, List<ИнфoрмацияОМетоде<T>>>[] Массив, ИнфoрмацияОМетоде<T> Им)
{
int минКолПарам = Им.КоличествоПараметров - 1;
foreach (var кв in Массив)
{
if (кв.Key < минКолПарам) continue;
var им = new ИнфoрмацияОМетоде<T>(Им, кв.Key);
кв.Value.Add(им);
}
}
void ДобавитьМетодыСпарамсВОбычныеМетоды()
{
var KV = ОбычныеМетоды.OrderBy(x => x.Key).ToArray();
foreach (var им in МетодыСParams)
{
ДобавитПарамсВСписок(KV, им);
}
foreach (var kv in KV)
{
kv.Value.Sort(new СравнительМетодов<T>());
}
}
public ВсеМетодыПоИмени(IEnumerable<T> методы)
{
foreach(var метод in методы)
{
var им = new ИнфoрмацияОМетоде<T>(метод);
if (им.hasParams)
{
МетодыСParams.Add(им);
var ОбычныйМетод = new ИнфoрмацияОМетоде<T>(им);
ДобавитьВСловарь(ОбычныйМетод, ОбычныйМетод.КоличествоПараметров);
}
else
{
ДобавитьВСловарь(им, им.КоличествоПараметров);
}
}
ДобавитьМетодыСпарамсВОбычныеМетоды();
МетодыСParams.Sort(new СравнительМетодовСпарамс<T>());
}
public ИнфoрмацияОМетоде<T> НайтиМетод(object[] параметрыОбъекты)
{
Type[] параметры = new Type[параметрыОбъекты.Length];
for (var i=0; i< параметрыОбъекты.Length; i++)
{
if (параметрыОбъекты[i] == null)
параметры[i] = null;
else
параметры[i] = параметрыОбъекты[i].GetType();
}
List<ИнфoрмацияОМетоде<T>> СписокМетодов;
if (ОбычныеМетоды.TryGetValue(параметры.Length, out СписокМетодов))
{
if (параметры.Length == 0) return СписокМетодов[0];
foreach (var метод in СписокМетодов)
{
if (метод.Сравнить(параметры))
return метод;
}
}
foreach (var метод in МетодыСParams)
{
if (метод.СравнитьПарамс(параметры))
return метод;
}
return null;
}
}
}
И вызов
public static void НайтиИВыполнитьМетод(ВсеМетодыПоИмени<MethodInfo> ВсеМетоды, params object[] параметры)
{
var метод = ВсеМетоды.НайтиМетод(параметры);
if (метод != null)
метод.ВыполнитьМетод(null, параметры);
}
public static void ТестПоискаМетода()
{
DynamicCall.SB.Clear();
var методы = typeof(DynamicCall).GetMethods().Where(x => x.Name == "CallA").ToArray();
var всеМетоды = new ВсеМетодыПоИмени<MethodInfo>(методы);
//DynamicCall.CallADynamic(1, 2);
//DynamicCall.CallADynamic(null, null);
//DynamicCall.CallADynamic(null, new object());double d = 6;
НайтиИВыполнитьМетод(всеМетоды, 2, d);
НайтиИВыполнитьМетод(всеМетоды, 1, 2);
НайтиИВыполнитьМетод(всеМетоды, null, null);
НайтиИВыполнитьМетод(всеМетоды, null, new object());
НайтиИВыполнитьМетод(всеМетоды, 1, new int[] { 1,2,3});
string ss = DynamicCall.SB.ToString();
}
Здравствуйте, Serginio1, Вы писали: S> С моим кодом пока работаю только я один. А я 1С ник. И мне удобнее работать с киррилицей. S>К хорошему привыкаешь быстро. Попробуй Какая гадость эта ваша заливая рыба(с)
Учитывая, что вся семантика шарпа на латинице (как это ни странно), любители непрерывно переключать раскладку несколько удивляют...
Не говоря уж о такой ерунде, как более лаконичный буржуйский язык
Здравствуйте, mDmitriy, Вы писали:
D>Учитывая, что вся семантика шарпа на латинице (как это ни странно), любители непрерывно переключать раскладку несколько удивляют...
Ну так сказано же:
С моим кодом пока работаю только я один.
Если человека устраивает, что ни в одном проекте подобный код не примут и даже читать не будут — зачем спорить?
Здравствуйте, mDmitriy, Вы писали:
D>Здравствуйте, Serginio1, Вы писали: S>> С моим кодом пока работаю только я один. А я 1С ник. И мне удобнее работать с киррилицей. S>>К хорошему привыкаешь быстро. Попробуй D>Какая гадость эта ваша заливая рыба(с) D>Учитывая, что вся семантика шарпа на латинице (как это ни странно), любители непрерывно переключать раскладку несколько удивляют... D>Не говоря уж о такой ерунде, как более лаконичный буржуйский язык
Просто ты не привык. В 1С наоборот плюются на латиницу.
А у меня «Руслиш»: официальный язык МКС
Не летать Вам в космос. А у меня есть шанс.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали: S> Просто ты не привык.
Нет... О вкусе устриц имеет смысл разговаривать с теми, кого от них не тошнит S> В 1С наоборот плюются на латиницу.
А куда им деваться, бедолагам — выбора-то нет S>А у меня «Руслиш»: официальный язык МКС S> Не летать Вам в космос. А у меня есть шанс.
В пределах земной орбиты — есть
А космос — он несколько масштабнее
Здравствуйте, mDmitriy, Вы писали:
D>Здравствуйте, Serginio1, Вы писали: S>> Просто ты не привык. D>Нет... О вкусе устриц имеет смысл разговаривать с теми, кого от них не тошнит S>> В 1С наоборот плюются на латиницу. D>А куда им деваться, бедолагам — выбора-то нет
Есть множество локализаций. В том числе украинская и казахская
Например я на 1С тоже пишу.
Процедура ExtractFields(S,aList,Delimiter,QuoteChar)
FieldStart=0; ScanField=1; ScanQuoted=2; EndQuoted=3;
//{initialize by clearing the string list, and
// starting in FieldStart state}
// Assert(aList <> nil, 'TDExtractFields: list is nil');
aList= новый Массив;
if ( (S=неопределено) или (СтрДлина(S) =0 )) Тогда
aList.Add("");
return;
КонецЕсли;
State = FieldStart;
// RStringBuilder SB= new RStringBuilder();
SB="";
StartPos=1;
EndPos=СтрДлина(S);
Inx=1;
// {read through all the characters in the string}
while (Inx <=EndPos) Цикл
// {get the next character}
Ch = Сред(S,Inx,1);
// {switch processing on the state}
Если State =FieldStart Тогда
if ( Ch = QuoteChar) Тогда
State = ScanQuoted;
StartPos=Inx+1;
SB="";
Inx=НайтиВПодстроке(S,StartPos,QuoteChar);
продолжить;
else
if ( Ch = Delimiter) Тогда
S>>А у меня «Руслиш»: официальный язык МКС S>> Не летать Вам в космос. А у меня есть шанс. D>В пределах земной орбиты — есть D>А космос — он несколько масштабнее
и солнце б утром не вставало, когда бы не было меня
S>Начну с того, что в 1С есть технология Внешних компонент Native API Технология создания внешних компонент Технология создания внешних компонент которые работают как под Windows так и под Linux
Сделал маршалинг из натива в манагед
namespace CoreClrDLL
{
// struct _tVariant
// {
// _ANONYMOUS_UNION union
// {
// int8_t i8Val;
// int16_t shortVal;
// int32_t lVal;
// int intVal;
// unsigned int uintVal;
// int64_t llVal;
// uint8_t ui8Val;
// uint16_t ushortVal;
// uint32_t ulVal;
// uint64_t ullVal;
// int32_t errCode;
// long hRes;
// float fltVal;
// double dblVal;
// bool bVal;
// char chVal;
// wchar_t wchVal;
// DATE date;
// IID IDVal;
// struct _tVariant *pvarVal;
// struct tm tmVal;
// _ANONYMOUS_STRUCT struct
// {
// void* pInterfaceVal;
// IID InterfaceID;
// }
// __VARIANT_NAME_2/*iface*/;
// _ANONYMOUS_STRUCT struct
// {
// char* pstrVal;
// uint32_t strLen; //count of bytes
//}
//__VARIANT_NAME_3/*str*/;
// _ANONYMOUS_STRUCT struct
// {
// WCHAR_T* pwstrVal;
//uint32_t wstrLen; //count of symbol
// } __VARIANT_NAME_4/*wstr*/;
// } __VARIANT_NAME_1;
// uint32_t cbElements; //Dimension for an one-dimensional array in pvarVal
//TYPEVAR vt;
//};public enum EnumVar
{
VTYPE_EMPTY = 0,
VTYPE_NULL,
VTYPE_I2, //int16_t
VTYPE_I4, //int32_t
VTYPE_R4, //float
VTYPE_R8, //double
VTYPE_DATE, //DATE (double)
VTYPE_TM, //struct tm
VTYPE_PSTR, //struct str string
VTYPE_INTERFACE, //struct iface
VTYPE_ERROR, //int32_t errCode
VTYPE_BOOL, //bool
VTYPE_VARIANT, //struct _tVariant *
VTYPE_I1, //int8_t
VTYPE_UI1, //uint8_t
VTYPE_UI2, //uint16_t
VTYPE_UI4, //uint32_t
VTYPE_I8, //int64_t
VTYPE_UI8, //uint64_t
VTYPE_INT, //int Depends on architecture
VTYPE_UINT, //unsigned int Depends on architecture
VTYPE_HRESULT, //long hRes
VTYPE_PWSTR, //struct wstr
VTYPE_BLOB, //means in struct str binary data contain
VTYPE_CLSID, //UUID
VTYPE_STR_BLOB = 0xfff,
VTYPE_VECTOR = 0x1000,
VTYPE_ARRAY = 0x2000,
VTYPE_BYREF = 0x4000, //Only with struct _tVariant *
VTYPE_RESERVED = 0x8000,
VTYPE_ILLEGAL = 0xffff,
VTYPE_ILLEGALMASKED = 0xfff,
VTYPE_TYPEMASK = 0xfff
};
public class РаботаСВариантами
{
public static object ПолучитьОбъекИзIntPtr(IntPtr Элемент)
{
IntPtr текПоз = Элемент + 44;
int размерIntPtr = Marshal.SizeOf<IntPtr>();
EnumVar тип =(EnumVar) Marshal.ReadInt16(текПоз);
switch (тип)
{
case EnumVar.VTYPE_EMPTY:
case EnumVar.VTYPE_NULL: return null;
case EnumVar.VTYPE_I2: return Marshal.ReadInt16(Элемент);
case EnumVar.VTYPE_I4: return Marshal.ReadInt32(Элемент);
case EnumVar.VTYPE_R4: return Marshal.PtrToStructure<float>(Элемент);
case EnumVar.VTYPE_R8: return Marshal.PtrToStructure<double>(Элемент);
case EnumVar.VTYPE_BOOL:return Marshal.ReadByte(Элемент)!=0;
case EnumVar.VTYPE_I1: return (sbyte)Marshal.ReadByte(Элемент);
case EnumVar.VTYPE_UI1: return Marshal.ReadByte(Элемент);
case EnumVar.VTYPE_UI2: return (UInt16)Marshal.ReadInt16(Элемент);
case EnumVar.VTYPE_UI4: return (UInt32)Marshal.ReadInt32(Элемент);
case EnumVar.VTYPE_I8: return Marshal.ReadInt64(Элемент);
case EnumVar.VTYPE_UI8: return (UInt64)Marshal.ReadInt64(Элемент);
case EnumVar.VTYPE_PWSTR: return Marshal.PtrToStringUni(Marshal.ReadIntPtr(Элемент));
case EnumVar.VTYPE_BLOB:
текПоз = Элемент + размерIntPtr;
byte[] res = new byte[Marshal.ReadInt32(текПоз)];
Marshal.Copy(Marshal.ReadIntPtr(Элемент), res,0,res.Length);
return res;
}
return null;
}
}
}
static object[] ПолучитьМассивПараметров(IntPtr МассивПараметров, int РазмерМассива)
{
var result = new object[РазмерМассива];
IntPtr ТекПоз = МассивПараметров;
for (var i=0; i< result.Length; i++)
{
result[i] = РаботаСВариантами.ПолучитьОбъекИзIntPtr(ТекПоз);
ТекПоз += 48;
}
return result;
}
public static bool CallAsFunc(int Target, IntPtr ИмяМетодаPtr, IntPtr ReturnValue, IntPtr МассивПараметров,int РазмерМассива)
{
string ИмяМетода = Marshal.PtrToStringUni(ИмяМетодаPtr);
var параметры = ПолучитьМассивПараметров(МассивПараметров, РазмерМассива);
return true;
}
public struct ЭлементХранилища
{
internal AutoWrap Объект;
internal int Next;
internal ЭлементХранилища(AutoWrap Объект)
{
this.Объект = Объект;
Next = -1;
}
internal ЭлементХранилища(AutoWrap Объект, int next)
{
this.Объект = Объект;
Next = next;
}
}
internal class ХранилищеОбъектов
{
List<ЭлементХранилища> Элементы= new List<ЭлементХранилища>();
int FirstDeleted = -1;
public int Add(AutoWrap Объект)
{
var элемент = new ЭлементХранилища(Объект);
if (FirstDeleted == -1)
{ Элементы.Add(элемент);
return Элементы.Count-1;
}
else
{
int newPos = FirstDeleted;
FirstDeleted = Элементы[newPos].Next;
Элементы[newPos] = элемент;
return newPos;
}
}
public void RemoveKey(int Pos)
{
if (Pos > -1 && Pos < Элементы.Count && Элементы[Pos].Объект != null)
{
var Элемент = new ЭлементХранилища(null, FirstDeleted);
Элементы[Pos] =Элемент;
FirstDeleted = Pos;
}
}
public AutoWrap GetValue(int Pos)
{
if (!(Pos > -1 && Pos < Элементы.Count && Элементы[Pos].Объект != null))
return null;
return Элементы[Pos].Объект;
}
}
Создал класс обертку
public class AutoWrap
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate IntPtr ВыделитьПамятьDelegate(int КоличествоБайтов);
internal static ХранилищеОбъектов СписокОбъектов;
internal static int ХэшДляСсылки=new Guid().GetHashCode();
protected internal object O = null;
protected internal Type T = null; // Тип может быть и интерфейсомprotected internal int ИндекасВСписке;
internal bool ЭтоТип;
internal bool IsEnum;
internal bool ЭтоExpandoObject;
internal static bool ЭтоСемерка = false;
internal static bool ВыводитьСообщениеОбОшибке = true;
internal static Exception ПоследняяОшибка = null;
internal static ВыделитьПамятьDelegate ВыделитьПямять;
public static void SetDelegate(IntPtr ДляВыделенияПамяти)
{
ВыделитьПямять = Marshal.GetDelegateForFunctionPointer<ВыделитьПамятьDelegate>(ДляВыделенияПамяти);
}
static AutoWrap()
{
СписокОбъектов = new ХранилищеОбъектов();
var первый = new AutoWrap(typeof(NetObjectToNative));
}
public AutoWrap(object obj)
{
ИндекасВСписке = СписокОбъектов.Add(this);
O = obj;
if (O is Type)
{
T = O as Type;
ЭтоТип = true;
}
else
{
T = O.GetType();
ЭтоТип = false;
ЭтоExpandoObject = O is System.Dynamic.ExpandoObject;
IsEnum = T.GetTypeInfo().IsEnum;
}
Экспортируются функции
public static bool CallAsFunc(int Target, IntPtr ИмяМетодаPtr, IntPtr ReturnValue, IntPtr МассивПараметров, int РазмерМассива)
{
var AW = СписокОбъектов.GetValue(Target);
if (AW == null) return false;
bool IsReturnValue = ReturnValue != IntPtr.Zero;
string ИмяМетода = Marshal.PtrToStringUni(ИмяМетодаPtr);
var параметры = ПолучитьМассивПараметров(МассивПараметров, РазмерМассива);
object result = null;
List<int> ИзмененныеПараметры = new List<int>();
var res = AW.TryInvokeMember(ИмяМетода, параметры, out result, ИзмененныеПараметры);
if (!res) return false;
foreach( var i in ИзмененныеПараметры)
{
РаботаСВариантами.УстановитьОбъектВIntPtr(параметры[i], МассивПараметров+48*i);
}
if (IsReturnValue) РаботаСВариантами.УстановитьОбъектВIntPtr(ОбернутьОбъект(result), ReturnValue);
return true;
}
public static int GetNParams(int Target, IntPtr ИмяМетодаPtr)
{
var AW = СписокОбъектов.GetValue(Target);
if (AW == null) return -1;
string ИмяМетода = Marshal.PtrToStringUni(ИмяМетодаPtr);
return ИнформацияПоТипам.КоличествоПараметровДляМетода(AW.T, ИмяМетода);
}
public static bool SetPropVal(int Target, IntPtr ИмяСвойстваPtr, IntPtr pvarPropVal)
{
var AW = СписокОбъектов.GetValue(Target);
if (AW == null) return false;
string ИмяСвойства = Marshal.PtrToStringUni(ИмяСвойстваPtr);
object result = РаботаСВариантами.ПолучитьОбъекИзIntPtr(pvarPropVal);
var res = AW.TrySetMember(ИмяСвойства,result);
return res;
}
//---------------------------------------------------------------------------//public static bool GetPropVal(int Target, IntPtr ИмяСвойстваPtr, IntPtr varPropVal)
{
var AW = СписокОбъектов.GetValue(Target);
if (AW == null) return false;
string ИмяСвойства = Marshal.PtrToStringUni(ИмяСвойстваPtr);
object result = null;
var res = AW.TryGetMember(ИмяСвойства, out result);
if (!res) return false;
РаботаСВариантами.УстановитьОбъектВIntPtr(ОбернутьОбъект(result), varPropVal);
return true;
}
public static void DeleteObject(int Target)
{
СписокОбъектов.RemoveKey(Target);
}
Код на C#
var sB= new System.Text.StringBuilder();
sB.Append("Новая Строка");
var str=sB.ToString();
sB.Capacity=40;
var capacity=sB.Capacity
На С++ выглядит так
// Загрузим Core CLR
// И создадим домен
//Первый параметр это путь к папке с coreclr.dll
NetObjectToNative::ManagedDomainLoader* mD = NetObjectToNative::ManagedDomainLoader::InitManagedDomain(L"c:\\Program Files\\DNX\\runtimes\\dnx-coreclr-win-x86.1.0.0-rc1-update1\\bin\\", L"", L"");
if (!mD) return 0;
tVariant Params[4];
tVariant RetVal;
tVariant* paParams = Params;
paParams->vt = VTYPE_PWSTR;
paParams->pwstrVal = L"System.Text.StringBuilder";
cout << "Press Key";
cin.get();
// 0 это индекс вспомогательного класса для получения типов объектов и прочих удобный методовbool res=mD->pCallAsFunc(0, L"Новый", &RetVal, paParams, 1);
if(!res) return 0;
// Так как в 1С нет возможности установить пользовательский тип
// то возвращаем byte[12] который будет ID объекта
// первые четыре байта ХэшДляСсылки=new Guid().GetHashCode(); одинаковый для всех .Net объектов
// вторые 4 байта это хэш объекта
// третьи это индекс в списке экспортируемых объектов
// Можно его передавать в качестве параметра типа BLOB
byte ref[12];
memcpy(ref, RetVal.pstrVal, 12);
// Теперь мы можем передавать ссылку ref в параметрах;long* target =(long*)RetVal.pstrVal;
long Target = target[2]; // Получили индекс в списке
wprintf_s(L"index : %d\n", Target);
// Память выделяется на стороне натива. Нам и удалять.delete[] RetVal.pstrVal;
paParams->vt = VTYPE_PWSTR;
paParams->pwstrVal = L"Новая Строка";
// 0 так как вызывается как void даже если метод что то и возвращает, что бы не оборачивать результат
res = mD->pCallAsFunc(Target, L"Append", 0, paParams, 1);
res = mD->pCallAsFunc(Target, L"ToString", &RetVal, paParams, 0);
wprintf_s(L"index : %S\n", RetVal.pwstrVal);
delete[] RetVal.pstrVal;
paParams->vt = VTYPE_I4;
paParams->lVal =40;
res = mD->pSetPropVal(Target, L"Capacity", paParams);
res = mD->pGetPropVal(Target, L"Capacity", &RetVal);
wprintf_s(L"Capacity : %d\n", RetVal.lVal);
// Удалим объект из списка. Теперь его может собрать GC
mD->pDeleteObject(Target);
// Создадим объект через тип
paParams->vt = VTYPE_PWSTR;
paParams->pwstrVal = L"System.Text.StringBuilder";
// Получим ID оббъекта typeof(System.Text.StringBuilder)
res = mD->pCallAsFunc(0, L"ПолучитьТип", &RetVal, paParams, 1);
//paParams[0] = RetVal;
// Скопируем ID оббъекта typeof(System.Text.StringBuilder)
memcpy(ref, RetVal.pstrVal, 12);
// Установим ссылку в параметрах
paParams->vt = VTYPE_BLOB;
paParams->pstrVal =(char*) ref;
paParams->strLen = 12;
// И создадим экземпляр StringBuilder
res = mD->pCallAsFunc(0, L"Новый", &RetVal, paParams, 1);
if (!res) return 0;
// Выгрузим доменdelete mD;
return 0;
Думаю статью написать. Как для C++ лучше сделать обертку. Для 1С думаю доделать на этой неделе
и солнце б утром не вставало, когда бы не было меня
Но делегаты и структуры он умеет маршалить на не-windows платформах?
Если да, то можно описать на стороне C/C++ интерфейс (на C — структура с указателями на функции, на C++ сразу интерфейс — класс с чистыми вируальными методами), на стороне .NET описать native-"интерфейс" стуктуру/класс, с полями-делегатами соотв. методам в интерфейсе в C/C++.
Ключевое тут — чтобы Core CLR умел маршалить делегаты в структуре, "большой" .NEt это умеет, со 2-й версии точно.