diff --git a/src/OneScript.StandardLibrary/Collections/ValueList/ValueListImpl.cs b/src/OneScript.StandardLibrary/Collections/ValueList/ValueListImpl.cs index 6f3c1b288..d4d271104 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueList/ValueListImpl.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueList/ValueListImpl.cs @@ -13,6 +13,7 @@ This Source Code Form is subject to the terms of the using OneScript.Execution; using OneScript.Types; using OneScript.Values; +using OneScript.StandardLibrary.TypeDescriptions; using ScriptEngine.Machine; using ScriptEngine.Machine.Contexts; @@ -25,43 +26,74 @@ namespace OneScript.StandardLibrary.Collections.ValueList public class ValueListImpl : AutoCollectionContext { readonly List _items; + ulong _maxId; + public ValueListImpl() { _items = new List(); } - public override bool IsIndexed - { - get - { - return true; - } - } + public override bool IsIndexed => true; public override IValue GetIndexedValue(IValue index) { - if (index.SystemType == BasicTypes.Number) - { - return GetValue(index); - } - else - { - return base.GetIndexedValue(index); - } + return index is BslNumericValue ? GetValue(index) : base.GetIndexedValue(index); } public override void SetIndexedValue(IValue index, IValue val) { if (index.SystemType == BasicTypes.Number) + throw IndexedIsReadonlyException(); + + base.SetIndexedValue(index, val); + } + + /// + /// Определяет тип для значений, которые могут храниться в элементах данного списка значений + /// + /// ОписаниеТипов + [ContextProperty("ТипЗначения", "ValueType")] + public TypeDescription ListValueType { get; set; } = new(); + + ValueListImpl _availableValues; + + /// + /// Ограничивает допустимые значения для элементов данного списка значений. + /// Возможные значения: Неопределено - ограничения отсутствуют, + /// СписокЗначений - список допустимых значений + /// + /// + /// Проверка допустимости добавляемых значений производится после приведения к указанным в ТипЗначения (если есть) + /// + /// СписокЗначений или Неопределено + [ContextProperty("ДоступныеЗначения", "AvailableValues")] + public IValue AvailableValues + { + get { - throw new RuntimeException("Индексированное значение доступно только для чтения"); - } - else - { - base.SetIndexedValue(index, val); + if (_availableValues != null) + return _availableValues; + + return BslUndefinedValue.Instance; } - } + set + { + switch (value) + { + case BslUndefinedValue: + _availableValues = null; + break; + + case ValueListImpl vl: + _availableValues = vl; + break; + + default: throw RuntimeException.InvalidArgumentType(); + } + } + } + /// /// Получить элемент по индексу /// @@ -71,6 +103,9 @@ public override void SetIndexedValue(IValue index, IValue val) public ValueListItem GetValue(IValue index) { int numericIndex = (int)index.AsNumber(); + if (numericIndex < 0 || numericIndex >= _items.Count) + throw RuntimeException.IndexOutOfRange(); + return _items[numericIndex]; } @@ -103,22 +138,31 @@ public ValueListItem Add(IValue value = null, string presentation = null, bool c [ContextMethod("Вставить", "Insert")] public ValueListItem Insert(int index, IValue value = null, string presentation = null, bool check = false, IValue picture = null) { + if (index < 0 || index > _items.Count) + throw RuntimeException.IndexOutOfRange(); + var newItem = CreateNewListItem(value, presentation, check, picture); _items.Insert(index, newItem); return newItem; } - private static ValueListItem CreateNewListItem(IValue value, string presentation, bool check, IValue picture) + private ValueListItem CreateNewListItem(IValue value, string presentation, bool check, IValue picture) { - var newItem = new ValueListItem + var newValue = ListValueType.AdjustValue(value); + if (_availableValues is not null) + { + var foundItem = _availableValues.FindByValue(newValue); + newValue = foundItem is ValueListItem li ? li.Value : ListValueType.AdjustValue(); + } + + return new ValueListItem(_maxId++) { - Value = value ?? BslUndefinedValue.Instance, + Value = newValue, Presentation = presentation, Check = check, Picture = picture }; - return newItem; } /// @@ -126,10 +170,7 @@ private static ValueListItem CreateNewListItem(IValue value, string presentation /// /// Массив [ContextMethod("ВыгрузитьЗначения", "UnloadValues")] - public ArrayImpl UnloadValues() - { - return new ArrayImpl(_items.Select(x=>x.Value)); - } + public ArrayImpl UnloadValues() => new ArrayImpl(_items.Select(x => x.Value)); /// /// Загружает значения из массива @@ -139,17 +180,14 @@ public ArrayImpl UnloadValues() public void LoadValues(ArrayImpl source) { Clear(); - _items.AddRange(source.Select(x => new ValueListItem() { Value = x })); + _items.AddRange(source.Select(x => new ValueListItem(_maxId++) { Value = x })); } /// /// Удаляет все элементы из списка. /// [ContextMethod("Очистить", "Clear")] - public void Clear() - { - _items.Clear(); - } + public void Clear() => _items.Clear(); /// /// Устанавливает значение пометки у всех элементов списка значений @@ -170,10 +208,7 @@ public void FillChecks(bool check) /// ЭлементСпискаЗначений - Элемент списка значений, для которого необходимо определить индекс /// Число - Индекс в списке, если не найдено возвращает -1 [ContextMethod("Индекс", "IndexOf")] - public int IndexOf(ValueListItem item) - { - return _items.IndexOf(item); - } + public int IndexOf(ValueListItem item) => _items.IndexOf(item); /// /// Осуществляет поиск значения в списке @@ -194,11 +229,11 @@ private int IndexByValue(BslValue item) { int index; - if (item is ValueListItem) + if (item is ValueListItem listItem) { - index = IndexOf(item as ValueListItem); + index = IndexOf(listItem); if (index == -1) - throw new RuntimeException("Элемент не принадлежит списку значений"); + throw ElementDoesntBelongException(); } else { @@ -211,7 +246,7 @@ private int IndexByValue(BslValue item) throw RuntimeException.InvalidArgumentType(); } - if (index < 0 || index >= _items.Count()) + if (index < 0 || index >= _items.Count) throw RuntimeException.IndexOutOfRange(); } @@ -230,10 +265,9 @@ private int IndexByValue(BslValue item) public void Move(BslValue item, int offset) { int index_source = IndexByValue(item); - int index_dest = index_source + offset; - if (index_dest < 0 || index_dest >= _items.Count()) + if (index_dest < 0 || index_dest >= _items.Count) throw RuntimeException.InvalidNthArgumentValue(2); ValueListItem itemObject = _items[index_source]; @@ -273,26 +307,23 @@ public ValueListImpl Copy() [ContextMethod("СортироватьПоЗначению", "SortByValue")] public void SortByValue(IBslProcess process, SortDirectionEnum? direction = null) { - if (direction == null || direction == SortDirectionEnum.Asc) - { - _items.Sort((x, y) => SafeCompare(process, x.Value, y.Value)); - } - else - { - _items.Sort((x, y) => SafeCompare(process, y.Value, x.Value)); - } + _items.Sort( new ItemComparator(process, direction == null || direction == SortDirectionEnum.Asc) ); } - private int SafeCompare(IBslProcess p, IValue x, IValue y) + private class ItemComparator : IComparer { - try + readonly GenericIValueComparer _comparer; + readonly int _direction; + + public ItemComparator(IBslProcess process, bool ascending = true) { - return x.CompareTo(y); + _comparer = new GenericIValueComparer(process); + _direction = ascending ? 1 : -1; } - catch(RuntimeException) + + public int Compare(ValueListItem x, ValueListItem y) { - // Сравнение типов не поддерживается - return string.Compare(x?.AsString(p), y?.AsString(p), StringComparison.Ordinal); + return _comparer.Compare(x.Value, y.Value) * _direction; } } @@ -321,33 +352,34 @@ public void SortByPresentation(SortDirectionEnum? direction = null) /// Число - Индекс удаляемого элемента /// [ContextMethod("Удалить", "Delete")] - public void Delete(BslValue item) - { - int indexSource = IndexByValue(item); - - _items.RemoveAt(indexSource); - } + public void Delete(BslValue item) => _items.RemoveAt(IndexByValue(item)); #region Collection Context [ContextMethod("Количество", "Count")] - public override int Count() - { - return _items.Count; - } + public override int Count() => _items.Count; - public override IEnumerator GetEnumerator() - { - return _items.GetEnumerator(); - } + public override IEnumerator GetEnumerator() => _items.GetEnumerator(); #endregion + public override string ToString() => string.Join("; ", _items); + [ScriptConstructor] public static ValueListImpl Constructor() { return new ValueListImpl(); + } + + public static RuntimeException IndexedIsReadonlyException() + { + return new("Индексированное значение доступно только для чтения", "Indexed value is read-only"); } + public static RuntimeException ElementDoesntBelongException() + { + return new("Элемент не принадлежит списку значений", "Element does not belong to values list"); + } + } } diff --git a/src/OneScript.StandardLibrary/Collections/ValueList/ValueListItem.cs b/src/OneScript.StandardLibrary/Collections/ValueList/ValueListItem.cs index c015ee277..e394bacec 100644 --- a/src/OneScript.StandardLibrary/Collections/ValueList/ValueListItem.cs +++ b/src/OneScript.StandardLibrary/Collections/ValueList/ValueListItem.cs @@ -7,6 +7,8 @@ This Source Code Form is subject to the terms of the using System; using OneScript.Contexts; +using OneScript.Localization; +using OneScript.Values; using ScriptEngine.Machine; using ScriptEngine.Machine.Contexts; @@ -18,18 +20,29 @@ namespace OneScript.StandardLibrary.Collections.ValueList [ContextClass("ЭлементСпискаЗначений", "ValueListItem")] public class ValueListItem : AutoContext { + static readonly BilingualString EMPTY_VALUE_STRING = new("<Пустое значение>", ""); + private string _presentationHolder; private IValue _pictureHolder; + private readonly ulong _id; - public ValueListItem() + internal ValueListItem(ulong id) { + _id = id; _pictureHolder = ValueFactory.Create(); _presentationHolder = String.Empty; - } - + } + + /// + /// Хранимое элементом списка значение произвольного типа + /// [ContextProperty("Значение", "Value")] public IValue Value { get; set; } + /// + /// Строковое представление элемента списка значений. + /// Если не задано или указана пустая строка, то соответствует представлению значения. + /// [ContextProperty("Представление", "Presentation")] public string Presentation { @@ -37,17 +50,32 @@ public string Presentation set => _presentationHolder = value ?? String.Empty; } + /// + /// Связанное с элементом списка значение пометки. Тип: Булево + /// [ContextProperty("Пометка", "Check")] - public bool Check { get; set; } - + public bool Check { get; set; } + + /// + /// Картинка, связанная с элементом списка значений. + /// + /// Сейчас может содержать произвольное значение, не используется [ContextProperty("Картинка", "Picture")] public IValue Picture { get => _pictureHolder; set => _pictureHolder = value ?? ValueFactory.Create(); - } + } + + /// + /// Получает идентификатор для элемента списка значений, не привязанный к позиции элемента в списке + /// + [ContextMethod("ПолучитьИдентификатор", "GetID")] + public ulong GetID() => _id; public override string ToString() - => !String.IsNullOrEmpty(_presentationHolder) ? _presentationHolder : Value.ToString(); + => !String.IsNullOrEmpty(_presentationHolder) ? _presentationHolder + : Value is BslUndefinedValue or BslNullValue? EMPTY_VALUE_STRING + : Value.ToString(); } } diff --git a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs index 9e91465bb..c14c2223c 100644 --- a/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs +++ b/src/OneScript.StandardLibrary/TypeDescriptions/TypeDescription.cs @@ -5,7 +5,9 @@ This Source Code Form is subject to the terms of the at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ +using System; using System.Collections.Generic; +using System.Text; using OneScript.Contexts; using OneScript.Exceptions; using OneScript.StandardLibrary.Collections; @@ -329,10 +331,13 @@ private static void CheckAndAddOneQualifier(TypeDescriptionBuilder builder, IVal default: throw RuntimeException.InvalidNthArgumentType(nParam); } - } - } - - internal class UndefinedTypeAdjuster : IValueAdjuster + } + + public override string ToString() => string.Join(", ", _types); + } + + + internal class UndefinedTypeAdjuster : IValueAdjuster { public IValue Adjust(IValue value) { diff --git a/tests/value-list.os b/tests/value-list.os index 2dbf03562..edbfaf38c 100644 --- a/tests/value-list.os +++ b/tests/value-list.os @@ -17,9 +17,19 @@ ВсеТесты.Добавить("ТестДолжен_ПроверитьМетодСдвинутьСпискаЗначений"); ВсеТесты.Добавить("ТестДолжен_ПроверитьМетодСортироватьПоЗначениюСпискаЗначений"); ВсеТесты.Добавить("ТестДолжен_ПроверитьМетодСортироватьПоПредставлениюСпискаЗначений"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьСортировкуПоЗначениюРазныхТипов"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьСортировкуНеупорядочиваемыхТипов"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьМетодНайтиСпискаЗначений"); ВсеТесты.Добавить("ТестДолжен_ПроверитьМетодУдалитьСпискаЗначений"); ВсеТесты.Добавить("ТестДолжен_ПроверитьПреобразованиеЭлементаСпискаВСтроку"); + + ВсеТесты.Добавить("ТестДолжен_ПроверитьОшибкуМетодаПолучитьСпискаЗначений"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьСвойствоТипЗначения"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьСвойствоДоступныеЗначения_Без_ТипЗначения"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьСвойствоДоступныеЗначения_С_ТипЗначения"); + ВсеТесты.Добавить("ТестДолжен_ПроверитьПреобразованиеСпискаВСтроку"); + ВсеТесты.Добавить("ТестТестДолжен_ПроверитьМетодПолучитьИдентификатор"); Возврат ВсеТесты; КонецФункции @@ -148,6 +158,32 @@ юТест.ПроверитьРавенство(СЗ.Индекс(Э3), 2, "Метод Вставить() списка значений"); юТест.ПроверитьРавенство(СЗ.Индекс(Э4), 3, "Метод Вставить() списка значений"); + // Проверим ошибки + Ошибка = "Вставить с неверным индексом"; + Попытка + СЗ.Вставить(10, 9); + Исключение + Ошибка = ИнформацияОбОшибке().Описание; + КонецПопытки; + юТест.ПроверитьРавенство(Ошибка, "Значение индекса выходит за пределы диапазона"); + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьОшибкуМетодаПолучитьСпискаЗначений() Экспорт + + СЗ = Новый СписокЗначений; + СЗ.Добавить("Один"); + СЗ.Добавить("Два"); + + // Проверим ошибки + Ошибка = "Получить с неверным индексом"; + Попытка + СЗ.Получить(10); + Исключение + Ошибка = ИнформацияОбОшибке().Описание; + КонецПопытки; + юТест.ПроверитьРавенство(Ошибка, "Значение индекса выходит за пределы диапазона"); + КонецПроцедуры Процедура ТестДолжен_ПроверитьМетодУдалитьСпискаЗначений() Экспорт @@ -354,6 +390,50 @@ КонецПроцедуры +Процедура ТестДолжен_ПроверитьСортировкуПоЗначениюРазныхТипов() Экспорт + СЗ = Новый СписокЗначений; + + СЗ.Добавить(Тип("Строка")); + СЗ.Добавить("Стр2"); + СЗ.Добавить("СтрЪ"); + СЗ.Добавить(); + СЗ.Добавить(Новый Структура); + СЗ.Добавить(Новый Массив); + СЗ.Добавить(null); + СЗ.Добавить(Тип("Булево")); + СЗ.Добавить(Тип("Массив")); + СЗ.Добавить(Тип("ЗаписьXML")); + СЗ.Добавить(Новый ЧтениеJSON); + СЗ.Добавить(Новый ЗаписьXML); + + СЗ.СортироватьПоЗначению(); + + юТест.ПроверитьРавенство(СЗ[0].Значение, Неопределено); + юТест.ПроверитьРавенство(СЗ[1].Значение, null); + юТест.ПроверитьРавенство(СЗ[2].Значение, "Стр2"); + юТест.ПроверитьРавенство(СЗ[3].Значение, "СтрЪ"); + юТест.ПроверитьТип(СЗ[4].Значение, Тип("ЗаписьXML")); + юТест.ПроверитьТип(СЗ[5].Значение, Тип("Массив")); + юТест.ПроверитьТип(СЗ[6].Значение, Тип("Структура")); + юТест.ПроверитьТип(СЗ[7].Значение, Тип("ЧтениеJSON")); + юТест.ПроверитьРавенство(СЗ[8].Значение, Тип("Булево")); + юТест.ПроверитьРавенство(СЗ[9].Значение, Тип("ЗаписьXML")); + юТест.ПроверитьРавенство(СЗ[10].Значение, Тип("Массив")); + юТест.ПроверитьРавенство(СЗ[11].Значение, Тип("Строка")); +КонецПроцедуры + +// см. issue #1577 +Процедура ТестДолжен_ПроверитьСортировкуНеупорядочиваемыхТипов() Экспорт + СЗ = Новый СписокЗначений; + + СЗ.Добавить(Неопределено); + СЗ.Добавить(Неопределено); + + СЗ.СортироватьПоЗначению(); // не должно упасть + + юТест.ПроверитьРавенство(СЗ[0].Значение, Неопределено); + юТест.ПроверитьРавенство(СЗ[1].Значение, Неопределено); +КонецПроцедуры Процедура ТестДолжен_ПроверитьМетодСортироватьПоПредставлениюСпискаЗначений() Экспорт @@ -400,6 +480,10 @@ СЗ.Добавить(1, ""); СЗ.Добавить(2, Неопределено); СЗ.Добавить(3, " "); + СЗ.Добавить(Неопределено); + СЗ.Добавить(Неопределено,"(неопр.)"); + СЗ.Добавить(NULL); + СЗ.Добавить(NULL,"(null)"); юТест.ПроверитьРавенство("0", Строка(СЗ[0]), "Строка, без указания"); юТест.ПроверитьРавенство("", СЗ[0].Представление, "Представление, без указания"); @@ -409,5 +493,120 @@ юТест.ПроверитьРавенство("", СЗ[2].Представление, "Представление, Неопределено"); юТест.ПроверитьРавенство(" ", Строка(СЗ[3]), "Строка, пробел"); юТест.ПроверитьРавенство(" ", СЗ[3].Представление, "Представление, пробел"); + + юТест.ПроверитьРавенство("<Пустое значение>", Строка(СЗ[4]), "Неопределено, без указания"); + юТест.ПроверитьРавенство("", СЗ[4].Представление, "Неопределено, без представления"); + юТест.ПроверитьРавенство("(неопр.)", Строка(СЗ[5]), "Неопределено, с указанием"); + юТест.ПроверитьРавенство("(неопр.)", СЗ[5].Представление, "Неопределено, с представлением"); + + юТест.ПроверитьРавенство("<Пустое значение>", Строка(СЗ[6]), "NULL, без указания"); + юТест.ПроверитьРавенство("", СЗ[6].Представление, "NULL, без представления"); + юТест.ПроверитьРавенство("(null)", Строка(СЗ[7]), "NULL, с указанием"); + юТест.ПроверитьРавенство("(null)", СЗ[7].Представление, "NULL, с представлением"); + + +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьСвойствоТипЗначения() Экспорт + Описание = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(2)); + СЗ = Новый СписокЗначений; + СЗ.ТипЗначения = Описание; + СЗ.Добавить(12); + СЗ.Добавить(22); + СЗ.Добавить(122); + СЗ.Добавить("23"); + СЗ.Добавить("*3"); + + юТест.ПроверитьРавенство(12, СЗ[0].Значение); + юТест.ПроверитьРавенство(22, СЗ[1].Значение); + юТест.ПроверитьРавенство(99, СЗ[2].Значение); + юТест.ПроверитьТип(СЗ[3].Значение,"Число"); + юТест.ПроверитьРавенство(23, СЗ[3].Значение); + юТест.ПроверитьРавенство(0, СЗ[4].Значение); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьСвойствоДоступныеЗначения_Без_ТипЗначения() Экспорт + ДЗ = Новый СписокЗначений; + ДЗ.Добавить(11); + ДЗ.Добавить(12); + ДЗ.Добавить(99); + + СЗ = Новый СписокЗначений; + СЗ.ДоступныеЗначения = ДЗ; + СЗ.Добавить(12); + СЗ.Добавить(22); + СЗ.Добавить("11"); + + юТест.ПроверитьТип(СЗ[0].Значение,"Число"); + юТест.ПроверитьРавенство(12, СЗ[0].Значение, "Допустимое значение"); + юТест.ПроверитьРавенство( Неопределено, СЗ[1].Значение, "Недопустимое значение"); + юТест.ПроверитьРавенство( Неопределено, СЗ[2].Значение, "Без приведения типа"); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьСвойствоДоступныеЗначения_С_ТипЗначения() Экспорт + ДЗ = Новый СписокЗначений; + ДЗ.Добавить(11); + ДЗ.Добавить(12); + ДЗ.Добавить(99); + + Описание = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(2)); + + СЗ = Новый СписокЗначений; + СЗ.ТипЗначения = Описание; + СЗ.ДоступныеЗначения = ДЗ; + СЗ.Добавить(12); + СЗ.Добавить(22); + СЗ.Добавить("11"); // приведение типа + СЗ.Добавить(123); // переполнение + + юТест.ПроверитьТип(СЗ[0].Значение,"Число"); + юТест.ПроверитьРавенство(12, СЗ[0].Значение, "Допустимое значение"); + юТест.ПроверитьРавенство( 0, СЗ[1].Значение, "Недопустимое значение с приведением типа"); + юТест.ПроверитьТип(СЗ[2].Значение,"Число"); + юТест.ПроверитьРавенство( 11, СЗ[2].Значение, "Допустимое значение с приведением типа"); + юТест.ПроверитьРавенство( 99, СЗ[3].Значение, "Приведение с переполнением и допустимое значение"); +КонецПроцедуры + +Процедура ТестДолжен_ПроверитьПреобразованиеСпискаВСтроку() Экспорт + + СЗ = Новый СписокЗначений; + СЗ.Добавить(11); + СЗ.Добавить(12,"двенадцать"); + СЗ.Добавить("абв"); + СЗ.Добавить("фыв",""); + СЗ.Добавить("пробел"," "); + СЗ.Добавить("йцу","Йцу!"); + СЗ.Добавить(Неопределено); + СЗ.Добавить(Неопределено,"(неопр.)"); + + Строка = Строка(СЗ); + + юТест.ПроверитьРавенство(Строка, "11; двенадцать; абв; фыв; ; Йцу!; <Пустое значение>; (неопр.)"); +КонецПроцедуры + +Процедура ТестТестДолжен_ПроверитьМетодПолучитьИдентификатор() Экспорт + СЗ = Новый СписокЗначений; + + СЗ.Добавить(1); + СЗ.Добавить(-2); + СЗ.Добавить(3); + СЗ.Добавить(-4); + + СЗ.Удалить(2); + СЗ.Добавить(0); + + СЗ.СортироватьПоЗначению(); + + юТест.ПроверитьРавенство(-4, СЗ[0].Значение); + юТест.ПроверитьРавенство(3, СЗ[0].ПолучитьИдентификатор()); + + юТест.ПроверитьРавенство(-2, СЗ[1].Значение); + юТест.ПроверитьРавенство(1, СЗ[1].ПолучитьИдентификатор()); + + юТест.ПроверитьРавенство(0, СЗ[2].Значение); + юТест.ПроверитьРавенство(4, СЗ[2].ПолучитьИдентификатор()); + + юТест.ПроверитьРавенство(1, СЗ[3].Значение); + юТест.ПроверитьРавенство(0, СЗ[3].ПолучитьИдентификатор()); -КонецПроцедуры \ No newline at end of file +КонецПроцедуры \ No newline at end of file