.Net Core, 1C, динамическая компиляция, Scripting API

Очень часто приходится использовать динамический код в 1С, используя Выполнить или Вычислить. Аналогичная задача и для использования скриптов на .Net. Я постарался показать, как можно скрестить ежа с ужом и получить удобный код. В этой статье много вражеского кода для чистого одноэсника, но все когда-то бывает впервые.

Это продолжение статей Кроссплатформенное использование классов .Net в 1С через Native ВК. Или замена COM на Linux
Кроссплатформенное использование классов .Net в 1С через Native ВК. Или замена COM на Linux II
Асинхронное программирование в 1С через использование классов .Net из Native ВК
1С, Linux, Excel, Word, OpenXML, ADO, Net Core

На данный момент в .Net Core 2 варианта динамической компиляции 1. Это аналог CodeDom Microsoft.CodeAnalysis.CSharp.CSharpCompilation 
2. Roslyn Scripting Api. Примеры здесь

    var compilation = Microsoft.CodeAnalysis.CSharp.CSharpCompilation.Create("a")
.WithOptions(new Microsoft.CodeAnalysis.CSharp.CSharpCompilationOptions(Microsoft.CodeAnalysis    .OutputKind.DynamicallyLinkedLibrary))
.AddReferences(
Microsoft.CodeAnalysis.MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location))
.AddSyntaxTrees(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(
@"
using System;

public  class C
{

public  C(){}
public string  M()
{
return ""Hello Roslyn."";
}
}"));

var fileName = @"d:NetStandartTestCoreNetAppsrcTestCoreNetAppinDebug
etcoreapp1.0a.dll";

compilation.Emit(fileName);

var a = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath(fileName);


Type тип = a.GetType("C");
var obj = Activator.CreateInstance(тип);

var res = тип.GetMethod("M").Invoke(obj, null);
Console.WriteLine(res.ToString());

 Этот подход хорош, когда нужно обновить библиотеку. Но при этом создается DLL со всеми вытекающими.

 Второй способ мне нравится больше. Возьмем на примере получения делегата.

            string words = "надо заменить все первые буквы в словах на заглавные";
string pattern = @"w+";

var scr = Microsoft.CodeAnalysis.Scripting.ScriptOptions.Default;
var mscorlib = Assembly.Load(System.Runtime.Loader.AssemblyLoadContext.GetAssemblyName(@"c:UsersSmirnov_SA.nugetpackagesMicrosoft.NETCore.Portable.Compatibility1.0.1
ef
etcore50mscorlib.dll"));
scr =scr.WithReferences(mscorlib, typeof(MulticastDelegate).GetTypeInfo().Assembly, typeof(System.Runtime.CompilerServices.IStrongBox).GetTypeInfo().Assembly, typeof(MatchEvaluator).GetTypeInfo().Assembly, typeof(Regex).GetTypeInfo().Assembly)
.WithImports("System", "System.Text.RegularExpressions");


string КодДелегата = @"return (MatchEvaluator)((match) =>
{
string x = match.Value;
// If the first char is lower case...
if (char.IsLower(x[0]))
{
// Capitalize it.
return char.ToUpper(x[0]) + x.Substring(1, x.Length - 1);
}
return x;

});";
var result = Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript.EvaluateAsync(КодДелегата, scr).Result;
MatchEvaluator evaluator = (MatchEvaluator)result;

Console.WriteLine(Regex.Replace(words, pattern, evaluator));

 Обязательно нужно указать ссылки на:
   mscorlib.dll
   System.Private.CoreLib.ni.dll
   System.Runtime.dll 

 Для компиляции используются следующие библиотеки:
   «Microsoft.CodeAnalysis.CSharp»: «2.0.0-beta3»,
    «Microsoft.CodeAnalysis.CSharp.Scripting»: «2.0.0-beta3»,
    «Microsoft.CodeAnalysis.Scripting.Common»: «2.0.0-beta3»,
     Microsoft.CodeAnalysis.Scripting

   По динамической компиляции. В свое время работал с запчастями для автомобилей. А там куча поставщиков и клиентов. При этом прайсы на миллионы позиций. И каждый горазд давать данные в своем формате.  Было проще для каждого клиента создавать код,  записывать в справочник и использовать через Выполнить или Вычислить. Правда, при работе с миллионными прайсами этот подход тормозил.
 
Так или иначе приходилось писать DLL и работать через COM.

  C помощью динамической компиляции можно хранить текст кода и применять его в зависимости от условий. В том числе динамически формировать по условиям, а скомпилированный делегат можно кэшировать для повторного использования.

 Скорость компиляции достаточно высокая (кроме первого раза секунд 5).

 Перейдем к 1С. Так воторй алгоритм на 1С выглядит так

            стр  = "return (MatchEvaluator)((match) =>
|{
|  string x = match.Value;
|// If the first char is lower case...
|if (char.IsLower(x[0]))
|{
|// Capitalize it.
|return char.ToUpper(x[0]) + x.Substring(1, x.Length - 1);
|}
|return x;
|
|});";

текст = "надо заменить все первые буквы в словах на заглавные";
Образец = "w+";
// MatchEvaluator evaluator = (MatchEvaluator)ПолучитьДелегат();
ScriptOptions=ъТип("Microsoft.CodeAnalysis.Scripting.ScriptOptions","Microsoft.CodeAnalysis.Scripting");
CSharpScript=ъТип("Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript","Microsoft.CodeAnalysis.CSharp.Scripting");

scr = ъ(ScriptOptions.Default);
mscorlibСборка = ъ(Врап.Сборка("mscorlib.dll",Истина));
Private_CoreLibСборка=ъ(Врап.Сборка("System.Private.CoreLib.ni",Истина));
System_RuntimeСборка=ъ(Врап.Сборка("System.Runtime",Истина));
RegularExpressionsСборка=ъ(Врап.Сборка("System.Text.RegularExpressions",Истина));
Regex=ъ(RegularExpressionsСборка.GetType("System.Text.RegularExpressions.Regex"));
scr =ъ(scr.WithReferences(mscorlibСборка.ПолучитьСсылку(), Private_CoreLibСборка.ПолучитьСсылку(), System_RuntimeСборка.ПолучитьСсылку(), RegularExpressionsСборка.ПолучитьСсылку()));

scr =ъ(scr.WithImports("System", "System.Text.RegularExpressions"));

evaluator = ъ(ъ(CSharpScript.EvaluateAsync(стр, scr.ПолучитьСсылку())).Result);
Сообщить(Regex.Replace(текст, Образец, evaluator.ПолучитьСсылку()));

В общем, ничего особенного. Получили сборки, дали ссылки на них, скомпилировали, вызвали.

Перейдем к более сложным примерам. Так, в предыдущей статье я показывал примеры использования DocumentFormat.OpenXml на примере чтения Excel и Word.

Там была проблема в скорости из-за приведения строки к объекту через функцию, и сама скорость вызова из 1С в 5 раз медленнее её родного кода.

Поэтому вынесем большую часть кода в .Net. Аналогичный вариант есть на большом .Net  .Net в 1С. На примере использования HTTPClient,AngleSharp. Удобный парсинг сайтов с помощью библиотеки AngleSharp, в том числе с авторизацией аля JQuery с использованием CSS селекторов. Динамическая компиляция (пример в конце статьи).

Создадим класс и скопируем его в макет. Суть класса — прочитать данные ячеек и сгруппировать их по номеру строки

public class ДанныеЯчейки
{

public string ИмяЯчейки;
public string ИмяКолонки;
public int НомСтроки;
public string ЗначениеЯчейки;

}
public class ExcelReader
{
static Regex ШаблонКолонки = new Regex("[A-Za-z]+");
OpenXmlElementList ОбщиеСтроки;

void ЗаписатьДанныеАдреса(string адрес, ДанныеЯчейки данныеЯчейки)
{

данныеЯчейки.ИмяЯчейки = адрес;
var match = ШаблонКолонки.Match(адрес);
var ИмяКолонки = match.Value;
var НомерСтроки = int.Parse(адрес.Substring(ИмяКолонки.Length));
данныеЯчейки.ИмяКолонки = ИмяКолонки;
данныеЯчейки.НомСтроки = НомерСтроки;

}
void ДобавитьДанныеОбЯчейке(List<ДанныеЯчейки> ДанныеЭселя, Cell cell)
{
var адрес = cell.CellReference.InnerText;
var text = cell.CellValue?.Text;
var DataType = cell.DataType;
string res = text;
if (DataType != null && DataType == CellValues.SharedString)
{
int ssid = int.Parse(text);
res = ОбщиеСтроки[ssid].InnerText;
}

if (res == null) return;

var result = new ДанныеЯчейки();
ЗаписатьДанныеАдреса(адрес, result);
result.ЗначениеЯчейки = res;

ДанныеЭселя.Add(result);
}
public List<ДанныеЯчейки> ReadExcel(string fileName)
{
List<ДанныеЯчейки> ДанныеЭселя = new List<ДанныеЯчейки>();
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (SpreadsheetDocument doc = SpreadsheetDocument.Open(fs, false))
{
var workbookPart = doc.WorkbookPart;

// Строки хранятся отдельно
// В ячейках хранится индекс
var pt = workbookPart.GetPartsOfType<SharedStringTablePart>();
var sstpart = pt.First();
var sst = sstpart.SharedStringTable;
ОбщиеСтроки = sst.ChildElements;

var workbook = workbookPart.Workbook;

// Получим список страниц
var sheet = workbook.Descendants<Sheet>().First();

var worksheetPart = (DocumentFormat.OpenXml.Packaging.WorksheetPart)workbookPart.GetPartById(sheet.Id);

var worksheet = worksheetPart.Worksheet;

var cells = worksheet.Descendants<Cell>();


// One way: go through each cell in the sheet
foreach (Cell cell in cells)
{
ДобавитьДанныеОбЯчейке(ДанныеЭселя, cell);
}
}
}

return ДанныеЭселя;
}

static string НайтиИмяПоследнейКолонки(List<ДанныеЯчейки> Тз)
{
var рез = "";
var ДлинаРез = 0;
foreach (var стрТз in Тз)
{
var Стр = стрТз.ИмяКолонки;
var СтрДл = Стр.Length;

if (СтрДл > ДлинаРез)
{
ДлинаРез = СтрДл;
рез = Стр;
}
else if (СтрДл == ДлинаРез && string.Compare(Стр, рез, true) > 0)
рез = Стр;

}
return рез;
}

public static object ПолучитьДанныеЭкселя(string fileName)
{

var res = new ExcelReader();
var Данные = res.ReadExcel(fileName);
var данныеЭкселя = Данные.GroupBy(ё => ё.НомСтроки).Select(ъ => new { НомСтроки = ъ.Key, Ячейки = ъ.ToArray() }).OrderBy(ь => ь.НомСтроки);
var ИмяПоследнейКолонки = НайтиИмяПоследнейКолонки(Данные);
return new { ДанныеЁкселя = данныеЭкселя.ToList(), ИмяПоследнейКолонки = ИмяПоследнейКолонки };

}

}

return new Func<string, object>(ExcelReader.ПолучитьДанныеЭкселя);

Мы описали класс чтения и возвращаем ссылку на делегат, принимающий путь к файлу и возвращающий анонимный класс. Все равно в 1С мы будем работать с ним через рефлексию. Обратите внимание, что здесь описаны 2 класса.

Теперь вызовем этот код из 1С.

        ScriptOptions=ъТип("Microsoft.CodeAnalysis.Scripting.ScriptOptions","Microsoft.CodeAnalysis.Scripting");
CSharpScript=ъТип("Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript","Microsoft.CodeAnalysis.CSharp.Scripting");

scr = ъ(ScriptOptions.Default);
mscorlibСборка = ъ(Врап.Сборка("mscorlib.dll",Истина));
Private_CoreLibСборка=ъ(Врап.Сборка("System.Private.CoreLib.ni",Истина));
System_RuntimeСборка=ъ(Врап.Сборка("System.Runtime",Истина));
RegularExpressionsСборка=ъ(Врап.Сборка("System.Text.RegularExpressions",Истина));
OpenXmlСбока=ъ(Врап.Сборка("DocumentFormat.OpenXml.dll"));
LinqСбока=ъ(Врап.Сборка("System.Linq", истина));
FileSystemСбока=ъ(Врап.Сборка("System.IO.FileSystem", истина));

Regex=ъ(RegularExpressionsСборка.GetType("System.Text.RegularExpressions.Regex"));
scr =ъ(scr.WithReferences(mscorlibСборка.ПолучитьСсылку(), Private_CoreLibСборка.ПолучитьСсылку(), System_RuntimeСборка.ПолучитьСсылку(), RegularExpressionsСборка.ПолучитьСсылку(),OpenXmlСбока.ПолучитьСсылку(),LinqСбока.ПолучитьСсылку(),FileSystemСбока.ПолучитьСсылку()));
scr =ъ(scr.WithImports("System", "System.Collections.Generic", "System.Linq", "System.IO", "DocumentFormat.OpenXml", "DocumentFormat.OpenXml.Packaging", "DocumentFormat.OpenXml.Spreadsheet", "System.Text.RegularExpressions"));

Текст=ПолучитьМакет("ТекстКлассаЧтенияЕксель").ПолучитьТекст();

Делегат = ъ(ъ(CSharpScript.EvaluateAsync(Текст, scr.ПолучитьСсылку())).Result);
Данные= ъ(Делегат.DynamicInvoke(ИмяФайла));

Сообщить(Данные.ИмяПоследнейКолонки);

рез=новый ТаблицаЗначений;
ПоследняяКолонка=Данные.ИмяПоследнейКолонки;
СоздатьКолонки(рез.Колонки,ПоследняяКолонка);
Колонки=рез.Колонки;

Тз=ъ(Данные.ДанныеЁкселя);
Тз=ъ(Врап.ПолучитьЭнумератор(Тз.ПолучитьСсылку()));

сч=1;
// Получили сгруппированные данные по строкам
Пока Тз.MoveNext() Цикл
стрТз= ъ(Тз.Current);

НомСтроки=стрТз.НомСтроки;
Пока сч<НомСтроки Цикл
сч=сч+1;
рез.Добавить();
КонецЦикла;
сч=сч+1;
стр=рез.Добавить();

// получим ячейки по строке
ТзГр=ъ(стрТз.Ячейки);
ТзГр=ъ(Врап.ПолучитьЭнумератор(ТзГр.ПолучитьСсылку()));

Пока ТзГр.MoveNext() Цикл
стрТзГр= ъ(ТзГр.Current);
ИмяКолонки=стрТзГр.ИмяКолонки;
ЗначениеЯчейки=стрТзГр.ЗначениеЯчейки;
// Можно конечно получить индекс зная смещение символа 64 относительно 1 и 26 разрядную систему
// но найдем колонку по имени и её индекс
Колонка=Колонки.Найти(ИмяКолонки);
стр.Установить(Колонки.Индекс(Колонка),ЗначениеЯчейки);
КонецЦикла;
КонецЦикла;

Теперь скорость обработки Экселя значительно увеличилась, а затраты на компиляцию соизмеримы с затратами на чтения файлов.

Посмотрим процесс чтения Word. Не мудрствуя лукаво, я взял готовый класс здесь. Тем более там все на английском.

// Исходники можно скачать здесь
//https://code.msdn.microsoft.com/office/CSOpenXmlGetPlainText-554918c3/sourcecode?fileId=71592&pathId=851860130
public class GetWordPlainText : IDisposable
{
// Specify whether the instance is disposed.
private bool disposed = false;

// The word package
private WordprocessingDocument package = null;

/// <summary>
///  Get the file name
/// </summary>
private string FileName = string.Empty;

/// <summary>
///  Initialize the WordPlainTextManager instance
/// </summary>
/// <param name="filepath"></param>
public GetWordPlainText(string filepath)
{
this.FileName = filepath;
if (string.IsNullOrEmpty(filepath) || !File.Exists(filepath))
{
throw new Exception("The file is invalid. Please select an existing file again");
}

this.package = WordprocessingDocument.Open(filepath, true);
}

/// <summary>
///  Read Word Document
/// </summary>
/// <returns>Plain Text in document </returns>
public string ReadWordDocument()
{
StringBuilder sb = new StringBuilder();
OpenXmlElement element = package.MainDocumentPart.Document.Body;
if (element == null)
{
return string.Empty;
}

sb.Append(GetPlainText(element));
return sb.ToString();
}

/// <summary>
///  Read Plain Text in all XmlElements of word document
/// </summary>
/// <param name="element">XmlElement in document</param>
/// <returns>Plain Text in XmlElement</returns>
public string GetPlainText(OpenXmlElement element)
{
StringBuilder PlainTextInWord = new StringBuilder();
foreach (OpenXmlElement section in element.Elements())
{
switch (section.LocalName)
{
// Text
case "t":
PlainTextInWord.Append(section.InnerText);
break;

case "cr":                          // Carriage return
case "br":                          // Page break
PlainTextInWord.Append(Environment.NewLine);
break;

// Tab
case "tab":
PlainTextInWord.Append("	");
break;

// Paragraph
case "p":
PlainTextInWord.Append(GetPlainText(section));
PlainTextInWord.AppendLine(Environment.NewLine);
break;

default:
PlainTextInWord.Append(GetPlainText(section));
break;
}
}

return PlainTextInWord.ToString();
}

#region IDisposable interface

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
// Protect from being called multiple times.
if (disposed)
{
return;
}

if (disposing)
{
// Clean up all managed resources.
if (this.package != null)
{
this.package.Dispose();
}
}

disposed = true;
}
#endregion

public static string GetText(string FileName)
{

using (var pt = new GetWordPlainText(FileName))
{

return pt.ReadWordDocument();
}
}
}

return new Func<string,string>(GetWordPlainText.GetText);

Но вернемся к Руслишу:

        ScriptOptions=ъТип("Microsoft.CodeAnalysis.Scripting.ScriptOptions","Microsoft.CodeAnalysis.Scripting");
CSharpScript=ъТип("Microsoft.CodeAnalysis.CSharp.Scripting.CSharpScript","Microsoft.CodeAnalysis.CSharp.Scripting");

scr = ъ(ScriptOptions.Default);
mscorlibСборка = ъ(Врап.Сборка("mscorlib.dll",Истина));
Private_CoreLibСборка=ъ(Врап.Сборка("System.Private.CoreLib.ni",Истина));
System_RuntimeСборка=ъ(Врап.Сборка("System.Runtime",Истина));
RegularExpressionsСборка=ъ(Врап.Сборка("System.Text.RegularExpressions",Истина));
OpenXmlСбока=ъ(Врап.Сборка("DocumentFormat.OpenXml.dll"));
LinqСбока=ъ(Врап.Сборка("System.Linq", истина));
FileSystemСбока=ъ(Врап.Сборка("System.IO.FileSystem", истина));

Regex=ъ(RegularExpressionsСборка.GetType("System.Text.RegularExpressions.Regex"));
scr =ъ(scr.WithReferences(mscorlibСборка.ПолучитьСсылку(), Private_CoreLibСборка.ПолучитьСсылку(), System_RuntimeСборка.ПолучитьСсылку(),OpenXmlСбока.ПолучитьСсылку(),FileSystemСбока.ПолучитьСсылку()));
scr =ъ(scr.WithImports("System", "System.Text",  "System.IO", "DocumentFormat.OpenXml", "DocumentFormat.OpenXml.Packaging"));

Текст=ПолучитьМакет("ТекстЧтенияВорд").ПолучитьТекст();

Делегат = ъ(ъ(CSharpScript.EvaluateAsync(Текст, scr.ПолучитьСсылку())).Result);
стр = Делегат.DynamicInvoke(ИмяФайла);

Текст=Новый ТекстовыйДокумент;
Текст.ДобавитьСтроку(стр);
Текст.Показать();

Основная задача указать ссылки на используемые сборки и пространство имен.

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

6 Comments

  1. cool.vlad4

    +1. все это прикольно. но ума не приложу, как в реале писать в итоге код таким образом . выходной код , напоминает код с которым я как-то сталкивался , — powershell , который динамически компилит огромную простыню C# кода , аналогично, производит всякие д

    Reply
  2. Serginio

    Ну проблема для начало в том, что в Native API нельзя возвращать объекты. Поэтому приходится возвращать строку и из неё создавать ВК.

    //1С при передаче по ссылке свойства ВК Список.Current
    // при выходе из метода присваивает  Список.Current значение переданное изначально
    // Поэтому помечаем входной параметр как Знач
    //Или же делать так, если методы изменить нельзя
    // То нужно присвоить значение переменной и вызвать метод передав в параметрах эту переменную
    //Стр=Список.Current;
    //Зазача=ъ(Стр);
    Функция Ъ(знач Ссылка)
    
    // Создаем объект по ссылке полученной из методов .Net классов
    //Физически это строка ёЁ<Ьъ>№_%)Э?&2 содержащее 12 символов для отделения их от других строк
    //и индекс в спике исполуемых объектов на стороне .Net
    
    рез = Новый(«AddIn.NetObjectToNative.NetObjectToNative»);
    // И установим ссылку
    рез.УстановитьСсылку(Ссылка);
    возврат  рез
    КонецФункции // СоздатьОбъектПоСсылке()
    

    Показать

    Кстати на данные момент я не могу написать DLL для Core .Net для использования OpenXML. Нужно, что бы компонент был в NuGet.

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

    Reply
  3. cool.vlad4

    (2) это да. вот и получается , что придется либо переизобретать тот же COM, либо делать подобные workaround. но просто выходной код получается, уж очень непростым для сопровождения. примеры-то простые. в более сложных случаях будет еще более увесистый код.

    Reply
  4. Serginio

    (3) Я это прекрасно понимаю. Вообще эти разработки для того, что бы подвинуть 1С к изменению своей политики. На самом деле нет особых причин не использовать объекты в параметрах или при возврате объекта из метода.

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

    1. Абсолютно не нужны методы FindMethod, FindProp, IsPropReadable, IsPropWritable, GetNParams, HasRetVal, GetParamDefValue

    Так как у методов

    bool CallAsProc

    bool CallAsFunc

    bool SetPropVal и bool GetPropVal есть возвращаемое значение об успешном выполнении

    Информация об ошибке возвращается через AddError.

    Да и вызов по индексу это анахронизм от IDiapatch, где было описание диспинтерфейсов для увеличения скорости вызова.

    2. При возвращении методами SetPropVal и GetPropVal исключение не вызывается

    3. Зачем-то происходит установка свойств там, где в коде этого не требуется.

    4. Вызывается метод как функция там, где метод вызывается как процедура.

    5. Один из основных — это нельзя вернуть и передать экземпляр ВК из методов ВК.

    Я лично не вижу никаких проблем. Определить значение для такого типа

    Показать

    Reply
  5. Serginio

    Кроме того

    Например практически все программисты 1С используют ComОбъект.

    По моей методе можно использовать

    NetОбъект,NetТип

    JavaОбъект,JavaТип

    И эти объявления будут реально кроссплатформенны.

    При это различия с ComОбъект минимальны. Имя класса равноценно комовскому ProgID. При этом нет ограничений на используемые типы.

    Ты можешь написать свою библиотеку поместить в определенное место и использовать её вместо COM. Без регистрации итд. Расширять возможности 1С станет легче.

    Например сейчас в конфигураторе куча функций, которые есть в стандартных библиотеках. При этом функционал 1С функций сильно недотягивает до стандартных библиотек.

    Учитывая кроссплатформенность можно использовать нетовские или явовские библиотеки везде где можно. Упрощая программирование.

    А что касается работы с HTTP,SMPT, JSON то эти библиотеки были задолго до того как 1С их реализовывала, при этом с ошибками и функционалом сильно недотягивающих до .Net или Java.

    Стоит ли тратить время на то, что можно взять из стандартных библиотек. А ведь можно легко расширить за счет своих сборок.

    При этом например нетовская библиотека весит всего 65 мегабайт, которую можно включить в дистрибутив и главное это кроссплатформенное решение. Причем нет ничего сложного передавать в параметрах и объекты 1С которые поддерживают аналогичный интерфейс. Можно пойти по пути подсчета ссылок в 1С, а доступ к объектам 1С только на время вызова метода ВК.

    Например Использование сборок .NET в 1С 7.x b 8.x. Создание внешних Компонент многие бы использовали на равне с ComОбъект, но главная причина её неприменения в том, что она неинтегрирована в 1С.

    Даже если 1С не хочет интегрировать .Net в 1С, то можно сделать вариант ВК под .Net и Java . Прежде всего для получения объектов ВК и передачи их в параметрах. Кроме того можно добавить доступ по индексу [], получения итератора.

    Reply
  6. Serginio

    (3) Код то будет аналогичным. Нужно просто добавить ссылки на используемые DLL и пространства имен.

    ссылки на DLL можно передавать в виде путей

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *