В .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 объектов или ВК