Использование классов .Net в 1С для новичков

В .Net есть классы, структуры (Value типы), перечисления. С точки зрения 1С их можно рассматривать как классы. Каждый класс характеризуется типом. По аналогии с 1С классы это справочники, документы и т.д. У классов могут быть статические методы и свойства и методы и свойства объекта. По аналогии с 1С статические методы это методы менеджера (НайтиПоКоду,НайтиПоНомеру), а методы объекта аналогичны методам объекта (Модифицированность, Удалить, Номер, Дата)
Использование классов .Net в 1С для новичков
Компьютер Chip. Фото с сайта nextthing.co

В  .Net есть классы, структуры (Value типы), перечисления. С точки зрения 1С их можно рассматривать как классы. Каждый класс характеризуется типом. По аналогии с 1С классы это справочники, документы и т.д.

У классов могут быть статические методы и свойства  и методы и свойства объекта. По аналогии с 1С статические методы это методы менеджера (НайтиПоКоду,НайтиПоНомеру), а методы объекта аналогичны методам объекта (Модифицированность, Удалить, Номер, Дата)

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

Каждый класс характеризуется именем класса, пространством имен и сборкой (размещение Dll, Exe).

Рассмотрим класс String https://msdn.microsoft.com/ru-ru/library/system.string(v=vs.110).aspx

Представляет текст как последовательность знаков Юникода.

Исходный код .NET Framework для этого типа см. в указанном источнике.

Пространство имен:   System
Сборка:  mscorlib (в mscorlib.dll)

Начнем сразу на примерах. Итак, для начала создадим объект, который будет обертывать объекты .Net в COM объекты.

врап=новый COMОбъект("NetObjectToIDispatch45");

Теперь получим тип System

String=Врап.ПолучитьТип("System.String");

Для понимания правильнее будет так

ПространствоИмен="System."; String=Врап.ПолучитьТип(ПространствоИмен+"String");

Кто работал с ФабрикаXDTO, то там тоже есть простанство имен и типы.

К типам, которые находятся в GAC, мы можем не указывать сборку, в которой она находится.

КлассНеГак=Врап.ПолучитьТипИзСборки(ПолноеИмяКласса,ПолноеИмяФайла)

Теперь мы можем вызвать статические методы.

Например, аналог  1С функции ПустаяСтрока

Сообщить(String.IsNullOrWhiteSpace(неопределено)); Сообщить(String.IsNullOrWhiteSpace(" "));

Вернет Истина.

Статические методы в справке https://msdn.microsoft.com/ru-ru/library/system.string(v=vs.110).aspx

Помечаются символом S.

К сожалению, есть проблемы с функциями, которые принимают параметры как массив params.

Например, у класса String есть статическая функция Format

У неё есть множество перегрузок.

https://msdn.microsoft.com/ru-ru/library/b1csw23d(v=vs.110).aspx

public static string Format(

               string format,

               params object[] args

)

Которая вызывается, когда параметров больше 3

При объявлении  параметра как params object[] мы можем задавать параметры через запятую.

Сообщить(String.Format("загружено {0} из {1} байт. {2} % complete...", e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage, 0));

Я добвил еще один неиспользуемый параметр 0, иначе последний параметр вывелся бы как System.Object[]

Для того, что бы исправлять такие ошибки я добавил  метод ВыполнитьМетод

Который принимает первым параметром тип или строковое представление типа ("System.String");

Вторым параметром имя метода, а дальше параметры для запрашиваемого метода

Сообщить(Врап.ВыполнитьМетод(String,"Format","загружено {0} из {1} байт. {2} % complete...", e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage));

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

Объект можно получить двумя способами

DateTime= Врап.ПолучитьТип("System.DateTime "); Дата=Врап.СоздатьОбъект(DateTime,2015,1,2);

или

Дата=Врап.СоздатьОбъект("System.DateTime",2015,1,2);

Следует учесть, что в 1С числовые типы, дата строки, булево, массивы этих типов и Com объекты возвращаются как родные. 

Поэтому если использовать объектные методы, например, String нужно обернуть его.

Например

ОбернутаяСтрока=Врап.ОбернутьЛюбойОбъект("Тестовая строка");

Теперь можно применить к ней объектные методы

Найдем первое вхождение строки "ст" начиная с 6 символа (Возвращает индекс с отсчетом от нуля первого вхождения значения указанной строки в данном экземпляре. Поиск начинается с указанной позиции знака.)

Сообщить(ОбернутаяСтрока.IndexOf("ст",5));

Вернет 9

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

http://professorweb.ru/my/csharp/charp_theory/level11/11_1.php

Возьмем для примера System.Collections.Generic.List<T>

https://msdn.microsoft.com/ru-ru/library/6sh2ey19(v=vs.110).aspx

В C# Для того, чтобы создать список строк

var список = new List<String>();

Можно посмотреть строковое представление класса

Список.GetType().ToString()

Или

typeof(List<String>).ToString();

он выдаст System.Collections.Generic.List`1[System.String]

Теперь мы можем использовать его

Список=Врап.СоздатьОбъект("System.Collections.Generic.List`1[System.String]"); Для сч=1 По 10 Цикл Список.Add(строка(сч)); КонецЦикла; Для каждого стр Из Список Цикл Сообщить(стр) КонецЦикла;

Но тоже можно добиться другим способом

Узнав строковое представление typeof(List<>).ToString()

System.Collections.Generic.List`1[T]

Оно совпадает с названием класса, только добавляется `1 это говорит, что дженерик поддерживает 1 неопределенный тип.

ListT=Врап.ПолучитьТип("System.Collections.Generic.List`1"); ListT=Врап.ТипКакОбъект(ListT); Список=Врап.СоздатьОбъект(ListT.MakeGenericType(String));

Нужно отметить, для того, что бы у объекта полученного как  ПолучитьТип был доступ к методам класса Type нужно его преобразовать через метод ListT=Врап.ТипКакОбъект(ListT); 

Так как в реализации обертки он отвечает за статические методы класса.

Аналогично можно создать и словарь Dyctionary, это типизированный аналог 1С Соответствие 

Dictionary<String,int>

Словарь= Врап.СоздатьОбъект("System.Collections.Generic.Dictionary`2[System.String,System.Int32]"); Для сч=1 По 10 Цикл Словарь.Add(строка(сч),сч); КонецЦикла; Для каждого стр Из Словарь Цикл Сообщить(стр.Key+"="+стр.Value) КонецЦикла; //Аналогично это можно достигнуть через СловарьT=Врап.ПолучитьТип("System.Collections.Generic.Dictionary`2"); Int32=Врап.ПолучитьТип("System.Int32"); СловарьT=Врап.ТипКакОбъект(СловарьT); Словарь=Врап.СоздатьОбъект(СловарьT.MakeGenericType(String,Int32));

Еще одна особенность работы с C# реализацией this[]

Например, в 1С мы не можем вызвать Список[0]. Доступ осуществляется через

get_Itemи set_Item

Список.set_Item(0,"1С+Net"); Сообщить(Список.get_Item(0));

Вот полный список классовSystem.Collections.Generic 

https://msdn.microsoft.com/ru-ru/library/system.collections.generic(v=vs.110).aspx

Регулярные выражения тоже часто применяются для поиска замены.

http://professorweb.ru/my/csharp/charp_theory/level4/4_10.php

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

input = "Добро пожаловать в наш магазин, вот наши цены: |1 кг. яблок - 20 руб. |2 кг. апельсинов - 30 руб. |0.5 кг. орехов - 50 руб."; pattern = "b(d+W?руб)"; regex = Врап.СоздатьОбъект("System.Text.RegularExpressions.Regex",pattern); // Получаем совпадения в экземпляре класса Match matches = regex.Matches(input); // отображаем все совпадения Для Каждого match in matches Цикл // Т.к. мы выделили в шаблоне одну группу (одни круглые скобки), // ссылаемся на найденное значение через свойство Groups класса Match Сообщить(match.Groups.get_Item(1).Value); КонецЦикла

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

В 1С нет явного аналога StringBuilder Предоставляет изменяемую строку символов.

В этом тесте нужно собрать строку из маленьких фрагментов строк. В 1С для соединения строк есть неявный аналог ЗаписьXML ЗаписатьБезОбработки.

Для  замера времени используем Stopwatch который замеряет время до миллисекунды

https://msdn.microsoft.com/ru-ru/library/system.diagnostics.stopwatch(v=vs.110).aspx

Процедура ВывестиВремя(врап,stopWatch) ts = stopWatch.Elapsed; String=Врап.ПолучитьТип("System.String"); // Format and display the TimeSpan value. elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10,0); Сообщить(elapsedTime); КонецПроцедуры Процедура StringBuilderНажатие(Элемент) // Вставить содержимое обработчика. врап=новый COMОбъект("NetObjectToIDispatch45"); КоличествоИтераций=200000; stopWatch = Врап.СоздатьОбъект("System.Diagnostics.Stopwatch"); стр=""; НачВремя=ТекущаяДата(); stopWatch.Start(); Для сч=1 по КоличествоИтераций Цикл стр=стр+Строка(сч); КонецЦикла; stopWatch.Stop(); ВремяВыполнения=ТекущаяДата()-НачВремя; Сообщить("Конкатенация ="+ВремяВыполнения+" сек. ДлинаСтр="+СтрДлина(Стр)); ВывестиВремя(врап,stopWatch); стр=""; НачВремя=ТекущаяДата(); stopWatch.Restart(); SB = врап.СоздатьОбъект("System.Text.StringBuilder"); Для сч=1 по КоличествоИтераций Цикл SB.Append(Строка(сч)); КонецЦикла; стр=SB.ToString(); stopWatch.Stop(); ВремяВыполнения=ТекущаяДата()-НачВремя; Сообщить("StringBuilder ="+ВремяВыполнения+" сек. ДлинаСтр="+СтрДлина(Стр)); ВывестиВремя(врап,stopWatch); НачВремя=ТекущаяДата(); stopWatch.Restart(); ЗаписьXML = Новый ЗаписьXML; ЗаписьXML.УстановитьСтроку(); Для сч = 1 по КоличествоИтераций Цикл ЗаписьXML.ЗаписатьБезОбработки(Строка(сч)); КонецЦикла; Стр = ЗаписьXML.Закрыть(); stopWatch.Stop(); ВремяВыполнения=ТекущаяДата()-НачВремя; Сообщить("ЗаписьXML ="+ВремяВыполнения+" сек. ДлинаСтр="+СтрДлина(Стр)); ВывестиВремя(врап,stopWatch); //Конкатенация =96 сек. ДлинаСтр=1 287 896 //00:01:36.22 //StringBuilder =10 сек. ДлинаСтр=1 287 896 //00:00:09.91 //ЗаписьXML =4 сек. ДлинаСтр=1 287 896 //00:00:04.40 КонецПроцедуры

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

Используем информацию о культуре .

https://msdn.microsoft.com/ru-ru/library/system.globalization.cultureinfo(v=vs.110).aspx

Но часто нужно получать с данных без учета культуры

Целое = 55333; Дробное = 66333.44; Строка = "абвгд"; Дата=ТекущаяДата(); CultureInfo=Врап.ПолучитьТип("System.Globalization.CultureInfo"); SB.AppendFormat(CultureInfo.InvariantCulture,"{0} {1} {2} {3}",Целое,Дробное,Строка,Дата,0); Сообщить(SB.ToString());

Получаем 

55333 66333.44 абвгд 01/26/2016 17:10:05

Стоит еще добавить приведение типа к Интерфейсу. На примере прохода по коллекции. Если в 1С можно пройтись через Для Каждого то для 7 ки этого сделать нельзя. Заодно понять как приводить к интерфейсу.

Так из документации мы знаем что List<T> поддерживает интерфейс IEnumerable

https://msdn.microsoft.com/ru-ru/library/system.collections.ienumerable(v=vs.100).aspx

Перечислимый=Врап.ПолучитьИнтерфейс(Список,"IEnumerable"); Перечислитель=Перечислимый.GetEnumerator(); // На всякий случай приведем к Интерфейсу IEnumerator Перечислитель=Врап.ПолучитьИнтерфейс(Перечислитель,"IEnumerator"); // Теперь можем пройтись по коллекции Пока Перечислитель.MoveNext() Цикл // Врап.ВСтроку вывоит строковое представление всех типов в том числе числовые, строки, неопределено Сообщить(Врап.ВСтроку(Перечислитель.Current)); КонецЦикла; // Для того что бы получить методы объекта реализующего интерфейс можно // спомощью метода ОбновитьДанныеОметодахИСвойствах(object objOrig) // Для того что бы получить массив String[] можно вызвать Массив=Список.ToArray(); Сообщить(Массив); // В 1С он будет определен как COMSafeArray VT_BSTR // Доступ к элементам массива также как и в COMSafeArray через GetValue и SetValue //https://msdn.microsoft.com/library/system.array(v=vs.100).aspx // Создать массив можно через метод врапера СоздатьМассив(object type, int length)

Еще в .Net для асинхронного программирования используют await и методы возвращающие Task<>

Для того, чтобы получить результат, нужно обратиться к свойству Result, если нужно подождать, то вызвать метод Wait()

https://msdn.microsoft.com/ru-ru/library/dd321424(v=vs.118).aspx

// Следует отметить, что не все типы из GAC модно подгрузить // Например System.Net.Http.HttpClient который находится с System.Net.Http.dll //Получить тип можно двумя способами // По полному имени //Клиент=Врап.СоздатьОбъект("System.Net.Http.HttpClient, System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); //Либо просто указать имя библиотеку в котором находится класс без полного пути //Тогда ПолучитьТипИзСборки будет искать в катаорге GAC HttpClient=Врап.ПолучитьТипИзСборки("System.Net.Http.HttpClient","System.Net.Http.dll"); Клиент=Врап.СоздатьОбъект(HttpClient); ДанныеРесурса=Клиент.GetStringAsync("https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx").Result; Сообщить(Врап.ВСтроку(ДанныеРесурса));

Стоит вспомнить про вложенные типы на примере System.Environment.SpecialFolder

Так для получения типа нужно разделять вложенный тип знаком плюс, а не точкой

Environment=Врап.ПолучитьТип("System.Environment"); SpecialFolder=Врап.ПолучитьТип("System.Environment+SpecialFolder"); Сообщить(Environment.GetFolderPath(SpecialFolder.CommonProgramFilesX86)); Сообщить(Environment.GetFolderPath(SpecialFolder.Desktop)); Сообщить(Environment.GetFolderPath(SpecialFolder.MyDocuments));

Используя System.IO.Path можно получить доступ к Temp директории

Path=Врап.ПолучитьТип("System.IO.Path"); Сообщить(Path.GetTempPath());

Там же много методов для манимулирования с наименованием файла, получение каталога, расширения, объединять строки в путь итд

Очень часто приходится использовать битовую операци OR

например 

AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate  

или

watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;  

Поэтому добавил метод OR. Теперь те же операции можно вызвать

DecompressionMethods= Врап.ПолучитьТип("System.Net.DecompressionMethods"); handler.AutomaticDecompression=Врап.OR(DecompressionMethods.GZip,DecompressionMethods.Deflate) ; или NotifyFilters=врап.ПолучитьТип("System.IO.NotifyFilters"); рез=Врап.OR(NotifyFilters.LastAccess,NotifyFilters.LastWrite,NotifyFilters.FileName,NotifyFilters.DirectoryName);

Надеюсь, данная статья поможет использовать классы .Net даже тем, кто не знает C#. Ничего сложного нет, но поможет сильно увеличить возможности 1С без написания COM объектов или ВК

Начать дискуссию