Здравствуйте, Sharov, Вы писали:
НС>>Название переменной db тебя не на какие мысли не навело? Например на то что там не IEnumerable, а IQueryable? S>И что IQueryable? Ну выполнится запрос на стороне бд и вернется результат и далее преобразуем в Person, почему не будет работать?
Здравствуйте, vaa, Вы писали:
vaa>На днях осознал, что инициализация при создании объекта vaa>
vaa>var person = new Person
vaa>{
vaa> Name = "Alice",
vaa> Age = 12
vaa>};
vaa>
vaa>ничем не лучше старого способа: vaa>
vaa>var person = new Person();
vaa> person.Name = "Alice";
vaa> person.Age = 12;
vaa>
vaa>код даже короче.
Первый вариант это statement, второй — expression, со всеми вытекающими типа возможности использования в expression tree или для инициализации анонимных типов.
Здравствуйте, Sharov, Вы писали:
S>Т.е. в случае IQueryable компилятор вообще что ли код не будет генерировать, а это будет делать соотв. провайдер (транслятор из C# в sql, например)?
Здравствуйте, vaa, Вы писали:
vaa>Может пора провести ревизию и выкинуть ненужное из шарпов?
В первом случае ты гарантированно не забудешь поставить нужный параметр при создании объекта, ты должен не забыть все элементы конструктора
чтобы объект был проинициализирован, иначе все свалится при компиляции и даже до нее ошибка появится в IDE. Во втором случае забудешь и будет там какой нидь null или вообще левое значение по умолчанию.
В первом случае Person может быть иммутабельным, во втором случае он мутабелен. А если делать иммутабельно, то будут костыли с билдерами что не очень красиво, читаемо, громоздко да еще и медленнее.
Здравствуйте, vaa, Вы писали:
vaa>На днях осознал, что инициализация при создании объекта vaa>ничем не лучше старого способа: vaa>код даже короче. vaa>Может пора провести ревизию и выкинуть ненужное из шарпов?
Вопрос же не в короткости кода, а в том что это выражение. Можно например
var res = CallMethod( new Person{ Name = "Test" } );
а появились они, емнип, при внедрении linq, что позволило создавать выражения типа:
var q = from p in data.Persons
where p.Age > 65
select new PersonDto
{
Name = p.Name,
Age = p.Age
};
Здравствуйте, Sharov, Вы писали:
S>>>Что не так? Все компилируется. НС>>Название переменной db тебя не на какие мысли не навело? Например на то что там не IEnumerable, а IQueryable? S>И что IQueryable? Ну выполнится запрос на стороне бд и вернется результат и далее преобразуем в Person, почему не будет работать?
Нет, это ломает всю идею IQueryable. Оно должно быть expression tree — это дает возможность (хотя бы теоретическую) преобразовать запрос во что-то, исполняемое на сервере.
.Select( x => new Dto{ x.Age } )
так можно, потому что есть дерево выражений и можно написать преобразователь его в, например, SQL. Или еще какой там серверный язык запросов.
а если
.Select( x => { return new Dto{ x.Age }; } )
то что там происходит в лямбде — темный лес и преобразовать его ни во что нельзя, только создание на клиенте. Но тогда это уже не IQueryable по сути своей.
Потому такой синтаксис доступен только для IEnumerable.
Попробуй у себя сделать list.AsQueryable().Select( ... ) и увидишь что больше не компилируется.
Здравствуйте, elmal, Вы писали:
E>Здравствуйте, vaa, Вы писали:
vaa>>Может пора провести ревизию и выкинуть ненужное из шарпов? E>В первом случае ты гарантированно не забудешь поставить нужный параметр при создании объекта, ты должен не забыть все элементы конструктора E>чтобы объект был проинициализирован, иначе все свалится при компиляции и даже до нее ошибка появится в IDE. Во втором случае забудешь и будет там какой нидь null или вообще левое значение по умолчанию.
в первом случае необязательно задавать значения всех полей. и вроде никогда такого не было. Это реализовано в record причем через конструктор.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, vaa, Вы писали:
vaa>>если это разумно
НС>А если нет?
По ситуации.
Начнем с того, а точно нужен класс с 40 полями?
Ну и сразу же становится ясна культура сишарп разработчика.
вместо того чтобы написать корректный конструктор,
просто запихаем все данные в класс и будем на каждом этапе
валидировать и передавать дальше новую ДТО.
С другой стороны, да хоть сто, а завтра еще в одном месте нужно будет инициализировать этот класс.
и что? копипаста?
Здравствуйте, vaa, Вы писали: vaa>Начнем с того, а точно нужен класс с 40 полями?
А что вы предложите в качестве model для формы с 40 полями? vaa>Ну и сразу же становится ясна культура сишарп разработчика.
? vaa>вместо того чтобы написать корректный конструктор,
Непонятна ложная дилемма. Конструктор Person() вполне себе корректен — порождает новый экземпляр Person со всеми атрибутами, установленными в default.
С чего вы взяли, что корректного конструктора нет? vaa>просто запихаем все данные в класс и будем на каждом этапе vaa>валидировать и передавать дальше новую ДТО.
Не очень понятно, о какой валидации идёт речь, и что там за "каждый этап". vaa>С другой стороны, да хоть сто, а завтра еще в одном месте нужно будет инициализировать этот класс.
Ну да, нужно будет в ещё одном. vaa>и что? копипаста?
А какие варианты? Вы думаете, что вызов конструктора с позиционными аргументами будет чем-то лучше, чем object initializer?
Если вы собрались вызывать конструктор с именованными аргументами, то там "копипасты" будет ровно столько же, как и в object initializer.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vaa, Вы писали:
vaa>Культура в том, что инициализатор объекта позволяет задавать любые значения, в том числе некорректные,
Некорректность — понятие относительное. Логику проверки корректности засовывать в DTO, к примеру — скорее всего плохая идея.
НС>>Покажи корректный ктор на 40 полей. vaa>Не я придумал это сакральное число
Но ты заявил, что все ОК если конструктор корректный.
public class PersonA
{
public string Name { get; set; }
public int Age { get; set; }
}
public class PersonB
{
public string Name { get; set; }
public int Age { get; set; }
}
internal class Program
{
#region Methods
private static void Main(string[] args)
{
var list = new List<PersonA>(16);
for (int i = 0; i < 10; i++)
{
list.Add(new PersonA(){Age = i,Name = i.ToString()});
}
IEnumerable<PersonB> q = list.Select(p =>
{
var temp = new PersonB();
temp.Age = p.Age;
temp.Name = p.Name;
return temp;
});
}
Здравствуйте, vaa, Вы писали:
vaa>если у вас есть сущность person типа Person, возникает вопрос зачем вам его преобразовывать еще в какое-то DTO или анонимный тип.
Непонятен вопрос. Если ты нагородил rich domain model, то ты ССЗБ, вне зависимости от наличия или отсутствия конструктора. А вот если нет, то никакой отдельной специальной сущности у нас нет.
НС>>Но ты заявил, что все ОК если конструктор корректный. vaa>Встречный вопрос: что плохого в конструкторе с 40-50-60 полями в сравнении с инициализатором объекта, кроме случая анонимного типа?
Например то, что в каждой конкретной ситцуации может понадобится сильно меньше полей.
Здравствуйте, vaa, Вы писали: S>> А зачем гарантия? Зачем заполнять дефолтные значения заного?
vaa>Логика программы на что-то должна опираться? vaa>Чем городить проверки на каждом этапе, лучше разрешить только валидные значения на входе.
Так дефолтные вполне себе валидные. Нужно дать только те которые отличаются от дефолтных.
Так и в разного рода оборудовании итд где огромное количество параметров.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Leporidae, Вы писали:
vaa>>Логика программы на что-то должна опираться? vaa>>Чем городить проверки на каждом этапе, лучше разрешить только валидные значения на входе.
L>И как абсолютно ненужный повторяющийся код гарантирует тебе нужные значения? И чем дефолтные значения для тебя невалидные?
в том, что класс это набор св-в, которые представляют собой сумму всех возможных значений, и чем больше вариантов, а это произведение значений каждого св-ва,
тем сложнее реализовать логику которая обработает их все. ведь в современных яп ничего кроме IF ELSE пока не придумали.
Здравствуйте, Евгений Акиньшин, Вы писали:
ЕА>Здравствуйте, vaa, Вы писали:
vaa>>Здравствуйте, Евгений Акиньшин, Вы писали:
ЕА>>>а такое на старом шарпе написать:
ЕА>>>
ЕА>>>Person SomeMethod() => new() { Name = "Alice", Age = 12 };
ЕА>>>
vaa>>не лучший вариант, на мой взгляд.
ЕА>Ну да, но пришлось же обратную совместимость сохранять. ЕА>Вопрос же про сравнение со старым шарпом,а не с typescript.
согласен.
Person SomeMethod() { var person = new Person(); person.Name = "Alice"; person.Age = 12; return person; }
Здравствуйте, vaa, Вы писали:
vaa>На днях осознал, что инициализация при создании объекта vaa>
vaa>var person = new Person
vaa>{
vaa> Name = "Alice",
vaa> Age = 12
vaa>};
vaa>
vaa>ничем не лучше старого способа: vaa>
vaa>var person = new Person();
vaa> person.Name = "Alice";
vaa> person.Age = 12;
vaa>
vaa>код даже короче. vaa>Может пора провести ревизию и выкинуть ненужное из шарпов?
Во втором случае можем получить частично инициализированный объект Person (например, из-за исключения во втором присваивании), в первом — нет: либо полностью инициализированный объект, либо никакого.
Здравствуйте, jahr, Вы писали:
J>Во втором случае можем получить частично инициализированный объект Person (например, из-за исключения во втором присваивании), в первом — нет: либо полностью инициализированный объект, либо никакого.
Тогда уж лучше явно указать, что персон не всегда создается:
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, vaa, Вы писали:
vaa>>На днях осознал, что инициализация при создании объекта vaa>>ничем не лучше старого способа: vaa>>код даже короче.
_>
_>fn( new Person(Name="Alice",Age=12) );
_>
это на какой версии? именованные параметры вроде через двоеточие инициализируются.
Здравствуйте, vsb, Вы писали:
vsb>Ну как минимум лучше тем, что не нарушается принцип DRY. Грубо говоря — ты не сможешь опечататься в коде вида
Ну, если именовать так, то не мудрено. vsb>
Здравствуйте, vaa, Вы писали:
vsb>>Ну как минимум лучше тем, что не нарушается принцип DRY. Грубо говоря — ты не сможешь опечататься в коде вида vaa>Ну, если именовать так, то не мудрено.
Здравствуйте, elmal, Вы писали:
vaa>>Может пора провести ревизию и выкинуть ненужное из шарпов? E>В первом случае ты гарантированно не забудешь поставить нужный параметр при создании объекта, ты должен не забыть все элементы конструктора
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, vaa, Вы писали:
vaa>>На днях осознал, что инициализация при создании объекта vaa>>
vaa>>var person = new Person
vaa>>{
vaa>> Name = "Alice",
vaa>> Age = 12
vaa>>};
vaa>>
vaa>>ничем не лучше старого способа: vaa>>
vaa>>var person = new Person();
vaa>> person.Name = "Alice";
vaa>> person.Age = 12;
vaa>>
vaa>>код даже короче.
НС>Первый вариант это statement, второй — expression, со всеми вытекающими типа возможности использования в expression tree или для инициализации анонимных типов.
А в чем разница? Я думал, что компилятор первый код развернет во второй, т.е будет создана теневая переменная (temp), которая потом присвоится
person. Т.е.
var person = new Person
{
Name = "Alice",
Age = 12
};
развернется компилятором в
var temp = new Person();
temp.Name = "Alice";
temp.Age = 12;
person = temp;
Здравствуйте, fmiracle, Вы писали:
F>Здравствуйте, vaa, Вы писали:
vaa>>>>С другой стороны, инициализатор невозможно отлаживать.
vsb>>>Почему невозможно? vaa>>
vaa>> var x = new O{
vaa>> A = 1,
vaa>> B =2 <= как сюда поставить бряку?
vaa>>};
vaa>>
F>Вот как раз в этом случае проблемы нет — поставишь на всю "строку" из 4х строк и отладчик войдет в свойство B без проблем.
F>Неудобство тут только в том, что сперва он войдет в свойство A. Но это не "невозможность" отдалки а "некоторое неудобство иногда".
Ни разу не получается отладка. Еще раз проверил в vs code + net core 6. проскакивает инициализацию на ура. никуда при этом не заходит.
Person p = new Person
{
Name = "Alice",
Age = 12
};
Console.WriteLine("Hello, World!");
public class Person
{
public string Name { get; set; }
public uint Age { get; set; }
}
vaa>Ни разу не получается отладка. Еще раз проверил в vs code + net core 6. п
С .net работаю с visual studio, извини
vaa>роскакивает инициализацию на ура. никуда при этом не заходит. vaa>
vaa>Person p = new Person
vaa>{
vaa> Name = "Alice",
vaa> Age = 12
vaa>};
vaa>Console.WriteLine("Hello, World!");
vaa>public class Person
vaa>{
vaa> public string Name { get; set; }
vaa> public uint Age { get; set; }
vaa>}
vaa>
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, Sharov, Вы писали:
S>>А в чем разница? S>>Я думал, что компилятор первый код развернет во второй
НС>А если так? НС>
НС>db.Persons.Select(p => new Person { Name = "Alice", Age = 12 });
НС>
db.Persons.Select(p => {
var temp = new Person();
temp.Name = "Alice";
temp.Age = 12;
return temp;
});
Здравствуйте, fmiracle, Вы писали:
F>Здравствуйте, vaa, Вы писали:
vaa>>Ни разу не получается отладка. Еще раз проверил в vs code + net core 6. п
F>С .net работаю с visual studio, извини
vaa>>роскакивает инициализацию на ура. никуда при этом не заходит. vaa>>
vaa>>Person p = new Person
vaa>>{
vaa>> Name = "Alice",
vaa>> Age = 12
vaa>>};
vaa>>Console.WriteLine("Hello, World!");
vaa>>public class Person
vaa>>{
vaa>> public string Name { get; set; }
vaa>> public uint Age { get; set; }
vaa>>}
vaa>>
F>А, собственно, во что ты тут хочешь войти?
Вот как раз в этом случае проблемы нет — поставишь на всю "строку" из 4х строк и отладчик войдет в свойство B без проблем.
Здравствуйте, vaa, Вы писали:
vaa>Начнем с того, а точно нужен класс с 40 полями? vaa>Ну и сразу же становится ясна культура сишарп разработчика. vaa>вместо того чтобы написать корректный конструктор, vaa>просто запихаем все данные в класс и будем на каждом этапе vaa>валидировать и передавать дальше новую ДТО. vaa>С другой стороны, да хоть сто, а завтра еще в одном месте нужно будет инициализировать этот класс. vaa>и что? копипаста?
Ты как бы не путай класс с логикой и сложным внутренним состоянием, которое надо правильно конструировать и куда не надо влезать со стороны, и простой ДТО-объект, нужный для передачи данных.
Подветка началась с linq. Вот у нас есть linq-запрос, который выбирает данные для отчета. Каждый dto там представляет строку таблицы отчета, в ней 50 столбцов. Строку надо заполнить при выборке и прочитать при записи в файл/экран. И все. Вот нафига там конструктор?
Здравствуйте, vaa, Вы писали:
vaa>По ситуации. vaa>Начнем с того, а точно нужен класс с 40 полями? vaa>Ну и сразу же становится ясна культура сишарп разработчика.
При чем тут культура, если список полей определяется требованиями?
vaa>вместо того чтобы написать корректный конструктор,
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, vaa, Вы писали:
vaa>>По ситуации. vaa>>Начнем с того, а точно нужен класс с 40 полями? vaa>>Ну и сразу же становится ясна культура сишарп разработчика.
НС>При чем тут культура, если список полей определяется требованиями?
Я имел ввиду не количество полей.
Культура в том, что инициализатор объекта позволяет задавать любые значения, в том числе некорректные,
Хотя в справочнике Албахари написано, что он используется для упрощения создания объекта. И в чем же оно?
Объективно, эта техника разумна только в случае создания анонимных типов.
Именованные классы как правило используются в нескольких методах,
и тогда нормальный конструктор позволяет избавиться от дублирования кода.
vaa>>вместо того чтобы написать корректный конструктор,
НС>Покажи корректный ктор на 40 полей.
Здравствуйте, Ночной Смотрящий, Вы писали:
S>>Что не так? Все компилируется. НС>Название переменной db тебя не на какие мысли не навело? Например на то что там не IEnumerable, а IQueryable?
И что IQueryable? Ну выполнится запрос на стороне бд и вернется результат и далее преобразуем в Person, почему не будет работать?
Здравствуйте, Ночной Смотрящий, Вы писали:
S>>И что IQueryable? Ну выполнится запрос на стороне бд и вернется результат и далее преобразуем в Person, почему не будет работать? НС>Потому что не скомпилируется.
Ага, благодарю, понял. Круто, т.е. это спец. синтаксический сахар для деревьев выражений, т.е. чтобы провайдер мог сгенерировать соотв. код.
С др. стороны -- https://www.geeksforgeeks.org/object-and-collection-initializer-in-c-sharp/ (то, как я это описал).
Т.е. в случае IQueryable компилятор вообще что ли код не будет генерировать, а это будет делать соотв. провайдер (транслятор из C# в sql, например)?
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, vaa, Вы писали:
vaa>>Культура в том, что инициализатор объекта позволяет задавать любые значения, в том числе некорректные,
НС>Некорректность — понятие относительное. Логику проверки корректности засовывать в DTO, к примеру — скорее всего плохая идея.
внутри метода, анонимные типы для выборки из orm возможно, хотя и тут вопрос,
если у вас есть сущность person типа Person, возникает вопрос зачем вам его преобразовывать еще в какое-то DTO или анонимный тип.
Тогда это не сущность никакая, а банальный Typed DataSet.
НС>>>Покажи корректный ктор на 40 полей. vaa>>Не я придумал это сакральное число
НС>Но ты заявил, что все ОК если конструктор корректный.
Встречный вопрос: что плохого в конструкторе с 40-50-60 полями в сравнении с инициализатором объекта, кроме случая анонимного типа?
Здравствуйте, vaa, Вы писали:
vaa>На днях осознал, что инициализация при создании объекта vaa>
vaa>var person = new Person
vaa>{
vaa> Name = "Alice",
vaa> Age = 12
vaa>};
vaa>
vaa>ничем не лучше старого способа: vaa>
vaa>var person = new Person();
vaa> person.Name = "Alice";
vaa> person.Age = 12;
vaa>
vaa>код даже короче. vaa>Может пора провести ревизию и выкинуть ненужное из шарпов?
На самом деле в первом варианте еще и подсказочки есть на не добавленные свойства.
Ну и не вижу чем короче? person то добавлять надо. Мне эта фича нравится и использую особенно когда свойств значительно больше чем 2
и солнце б утром не вставало, когда бы не было меня
S> На самом деле в первом варианте еще и подсказочки есть на не добавленные свойства. S>Ну и не вижу чем короче? person то добавлять надо. Мне эта фича нравится и использую особенно когда свойств значительно больше чем 2
в том то и дело что только подсказки.
А должна быть гарантия:
var person = new Person("Alice");
public class Person
{
public string Name {get; set;}
public int Age {get; set;}
public Person(string name, int age = 0)
{
Name = string.IsNullOrEmpty(name) ? throw new Exception() : name;
Age = age < 0 ? throw new Exception() : age;
}
}
Считаю инициализация объекта оправдана только при создании экземпляров анонимных типов.
Здравствуйте, vaa, Вы писали:
vaa>Здравствуйте, Serginio1, Вы писали:
S>> На самом деле в первом варианте еще и подсказочки есть на не добавленные свойства. S>>Ну и не вижу чем короче? person то добавлять надо. Мне эта фича нравится и использую особенно когда свойств значительно больше чем 2 vaa>в том то и дело что только подсказки. vaa>А должна быть гарантия: vaa>
vaa>var person = new Person("Alice");
vaa>public class Person
vaa>{
vaa> public string Name {get; set;}
vaa> public int Age {get; set;}
vaa> public Person(string name, int age = 0)
vaa> {
vaa> Name = string.IsNullOrEmpty(name) ? throw new Exception() : name;
vaa> Age = age < 0 ? throw new Exception() : age;
vaa> }
vaa>}
vaa>
vaa>Считаю инициализация объекта оправдана только при создании экземпляров анонимных типов.
А зачем гарантия? Зачем заполнять дефолтные значения заного?
и солнце б утром не вставало, когда бы не было меня
vaa>>Считаю инициализация объекта оправдана только при создании экземпляров анонимных типов. S> А зачем гарантия? Зачем заполнять дефолтные значения заного?
Логика программы на что-то должна опираться?
Чем городить проверки на каждом этапе, лучше разрешить только валидные значения на входе.
Здравствуйте, vaa, Вы писали:
vaa>Логика программы на что-то должна опираться? vaa>Чем городить проверки на каждом этапе, лучше разрешить только валидные значения на входе.
А еще лучше сдизайнить так, чтобы невалидных значений не существовало в принципе.
L>>И как абсолютно ненужный повторяющийся код гарантирует тебе нужные значения? И чем дефолтные значения для тебя невалидные? vaa>в том, что класс это набор св-в, которые представляют собой сумму всех возможных значений, и чем больше вариантов, а это произведение значений каждого св-ва,
И?
vaa>тем сложнее реализовать логику которая обработает их все. ведь в современных яп ничего кроме IF ELSE пока не придумали.
Придумали. В C# — это логику, которую можно навешивать на сами поля через в { set; } или декораторами.
Кусок модели, например:
public abstract class Holder
{
[LogMasked(ShowFirst = 3, PreserveLength = true)]
[MaxLength(200)]
[Required]
public string Name { get; set; }
public Bank Bank { get; set; }
public Contact Contact { get; set; }
[LogMasked(ShowFirst = 3, PreserveLength = false)]
public string VATNumber { get; set; }
...
Нафейхоа мне нужно писать
var holder = new Holder(); // или впихивать в конструктор нцать полей?
holder.Name = ...;
holder.Bank = new Bank();
holder.Bank.Address = ...
...
И что именно мне это даст с точки зрения гарантий по сравнению с
bank = new Bank
{
Name = data.BankName,
Address = data.BankAddress,
AccountHolderName = data.BankAccountHolderName,
BankAccounts = bankAccounts?.ToArray() ?? new BankAccount[] { }
};
return new Holder
{
Id = (uint)data.Id,
Name = data.Name,
Bank = bank,
Contact = contact,
...
Здравствуйте, Leporidae, Вы писали:
L>>>И как абсолютно ненужный повторяющийся код гарантирует тебе нужные значения? И чем дефолтные значения для тебя невалидные? vaa>>в том, что класс это набор св-в, которые представляют собой сумму всех возможных значений, и чем больше вариантов, а это произведение значений каждого св-ва,
L>И?
vaa>>тем сложнее реализовать логику которая обработает их все. ведь в современных яп ничего кроме IF ELSE пока не придумали.
L>Придумали. В C# — это логику, которую можно навешивать на сами поля через в { set; } или декораторами. Черная магия L>Нафейхоа мне нужно писать
в том что разницы никакой, но при этом вводится лишняя сущность усложняющая ЯП.
ну и опять же это магия которая вещь в себе. Зиг об этом хорошо пишет.
vaa>>>тем сложнее реализовать логику которая обработает их все. ведь в современных яп ничего кроме IF ELSE пока не придумали.
L>>Придумали. В C# — это логику, которую можно навешивать на сами поля через в { set; } или декораторами. vaa>Черная магия
Нет. Это является стандартными средствами языка.
L>>Нафейхоа мне нужно писать
vaa>в том что разницы никакой, но при этом вводится лишняя сущность усложняющая ЯП.
Разница значительная.
vaa>ну и опять же это магия которая вещь в себе. Зиг об этом хорошо пишет.
Это не магия. Это реально стандартные средства языка. Более того, в каждом пункте этой «магии» ты можешь зайти в исходный код, пройтись дебаггером и т.п. В коде, что я не привел, есть декораторы, которые мы писали сами для собственных нужд.
Ровна та самая логика, которая «должна обработать всё», но тебе почему-то это не нравится. А нравится писать абсолютно бесполезный повторяющийся код, который еще и никаких гарантий не дает.