|
Гуру-тест для программистов 1С по C#, на сообразительность. | ☑ | ||
---|---|---|---|---|
0
Гений 1С
гуру
15.01.21
✎
13:13
|
Итак, нужен рефакторинг кода.
Есть много кода, вида: if (cond1) { struct_A r; r.field1 = "aга"; r.field2 = false; } else if (cond2) { struct_B r; r.field1 = "aга"; r.field2 = false; } else { struct_C r; r.field1 = "aга" + "мухоха"; //иногда код отличается для некоторых структур r.field2 = false; } Я придумал в итоге, как сделать красиво. Жду ваших гипотез. ООП (классы) не применял - из тушки по воробьям, считаю. Макросы нельзя в c#, увы. Но есть одно хитрое решение! ;-) |
|||
54
Ненавижу 1С
гуру
15.01.21
✎
16:08
|
(53) ну хорошо, что из того следует?
|
|||
55
Ненавижу 1С
гуру
15.01.21
✎
16:14
|
(53) ты так написал, что ТОЛЬКО для этого и используются
|
|||
56
Кирпич
15.01.21
✎
16:37
|
(53) Кому не лень, могут и в гугле перевести. Вы с гением не в одной палате лежите случайно?
|
|||
57
jbond
15.01.21
✎
16:49
|
(55) - такого мнения мелкософт.
У них же написано: Не используйте struct, кроме специальных случаев ... |
|||
58
Serginio1
15.01.21
✎
17:31
|
(57) struct удобны и для скорости и для уменьшения нагрузки на сборщик мусора.
После того как добавили ref return и ref struct Скорость выполнения приближается к С++ https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/builtin-types/struct#ref-struct https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/classes-and-structs/ref-returns https://docs.microsoft.com/ru-ru/dotnet/api/system.span-1?view=net-5.0 |
|||
59
Serginio1
15.01.21
✎
17:33
|
||||
60
ДедМорроз
15.01.21
✎
21:27
|
А зачем вообще рефакторить это ?
Если объекты разные и должны быть разными,то создавать в конструкторе. |
|||
61
ДедМорроз
15.01.21
✎
21:43
|
Ну и в Си++ структура - это класс,у которого все поля public.
То есть,на самом деле,особой разницы нет. Но в компиллируемых языках расточивание методов происходит в момент компилляции. |
|||
62
Serginio1
15.01.21
✎
22:47
|
(61) В С++ разницы практически нет. Структура это класс на стеке.
В .Net ограничения на структуру в том, что нет наследования. Любое приведение к object это боксинг и унбоксинг. Интерфейсы для структур только с боксингом. https://blogs.u2u.be/u2u/post/c-value-type-boxing-by-interfaces В свое время были эксперименты по размещению классов на стеке https://xoofx.com/blog/2015/10/08/stackalloc-for-class-with-roslyn-and-coreclr/ Но дальше не пошли |
|||
63
Кирпич
16.01.21
✎
06:41
|
(62) "Структура это класс на стеке." Вы совсем там трёхнулись на свом ООП? Структура это просто структура. Какая разница, на стеке она или ёё из кучи выделили.
|
|||
64
Ненавижу 1С
гуру
16.01.21
✎
07:16
|
(61) а причем здесь C++?
(63) в производительности, когда приведете к интерфейсу - она уедет в кучу, потом вернется обратно |
|||
65
Ненавижу 1С
гуру
16.01.21
✎
07:18
|
(63) ну и в семантике, например, присваивания
|
|||
66
Serginio1
16.01.21
✎
13:07
|
(63) Ну не правильно высказался. В С++ разницы между классом и структурой нет. Класс может как на стеке так и в памяти.
В C# структура только на стеке или как поле класса. А класс не может создаваться на стеке. Так понятно? Структуры нужны для скорости и уменьшения нагрузки на GC. В приведенном примере https://xoofx.com/blog/2015/10/08/stackalloc-for-class-with-roslyn-and-coreclr/ есть разница The stack version will run in 400 ms with 0 GC collect The heap version will run in 5000 ms with 100+ GC collect Например в Java нет структур и много мест где производительность проседает с большим количеством классов (массивы), по сравнению с value типами Меньше нагрузка на GC. И память выделяется одним огромным куском. |
|||
67
Кирпич
16.01.21
✎
14:08
|
(66) "В C# структура только на стеке или как поле класса."
С какого перепугу только на стеке? Я могу описать структуру и создавать её с помощью new. Разве нет?
|
|||
68
Кирпич
16.01.21
✎
14:12
|
Можно и так и так
|
|||
69
Ненавижу 1С
гуру
16.01.21
✎
14:16
|
(67) (68) подучись перед тем как писать такое. new само по себе не значит, что в куче
|
|||
70
Кирпич
16.01.21
✎
14:18
|
(69) А что же оно значит?
|
|||
71
Ненавижу 1С
гуру
16.01.21
✎
14:31
|
(70) оно для вызовов конструкторов
кстати, для структур .net поддерживает (в отличие от c#) конструкторы без параметров но скорее всего в (68) описано одно и тоже |
|||
72
Кирпич
16.01.21
✎
14:34
|
(71) А конструкторы где память выделяют? Не на стеке же ёптыть.
|
|||
73
Ненавижу 1С
гуру
16.01.21
✎
14:45
|
(72) а почему они ее выделяют?
Кстати: struct A { public int x; } A a1 = new A(); Console.WriteLine(a1.x); //ок A a2; Console.WriteLine(a2.x); //не ок |
|||
74
Кирпич
16.01.21
✎
14:51
|
(73) " Console.WriteLine(a2.x);//не ок"
Ну это примудрости C#. Он не дает печатать мусор из стека. Присвой значение a2.x и прокатит |
|||
75
Кирпич
16.01.21
✎
14:53
|
(73) "а почему они ее выделяют?"
Ну как бы под объект то надо выделить память, если он реально создается |
|||
76
Кирпич
16.01.21
✎
14:58
|
+(74) В C# стековые надо инициализировать. Даже такое не прокатит
|
|||
77
Ненавижу 1С
гуру
16.01.21
✎
14:58
|
(75) она уже выделена статически, как и под любую переменную
int x = 42; это тоже структура и тоже на стеке |
|||
78
Кирпич
16.01.21
✎
14:59
|
(77) Вот ты x инициализировал. А структуру не инициализировал. Потому и ругается.
|
|||
79
Ненавижу 1С
гуру
16.01.21
✎
15:01
|
(78) я про то, что локальные переменные типа структуры (value object) живут на стеке
|
|||
80
Кирпич
16.01.21
✎
15:03
|
(79) Если просто объявить, без new, то на стеке. Иначе будут в куче. Как я и писал в (68).
|
|||
81
Ненавижу 1С
гуру
16.01.21
✎
15:06
|
(80) продолжай в это верить
|
|||
82
Кирпич
16.01.21
✎
15:08
|
(81) А как по другому? Как правильно?
|
|||
83
Кирпич
16.01.21
✎
15:11
|
Структуры в C# всегда выделяются на стеке? Это же глупо и смешно.
|
|||
84
Ненавижу 1С
гуру
16.01.21
✎
15:12
|
(83) не всегда, как члены класса - живут в куче
|
|||
85
Serginio1
16.01.21
✎
15:13
|
(67) https://docs.microsoft.com/ru-ru/dotnet/standard/design-guidelines/choosing-between-class-and-struct
Первое различие между ссылочными типами и типами значений будет рассмотрено в том, что ссылочные типы выделяются в куче и уничтожаются сборщиком мусора, тогда как типы значений выделяются либо в стеке, либо в виде встроенных строк, содержащих типы, и освобождаются при освобождении стека или при освобождении содержащего их типа. Таким образом, выделение и освобождение типов значений являются общими дешевле, чем выделение и освобождение ссылочных типов. new для value типов это инициализатор https://stackoverflow.com/questions/203695/does-using-new-on-a-struct-allocate-it-on-the-heap-or-stack структуры не могут быть в памяти, только в качестве объекта боксинг. то есть var box= (object)( new A()); для конструкторов value типов применяется несколько инциализаторов в заваисмости где память выделяется newobj: Выделяет значение в стеке, вызывает параметризованный конструктор. Используется для промежуточных значений, например для присвоения полю или использования в качестве аргумента метода. call instance: Использует уже выделенное место хранения (будь то в стеке или нет). Это используется в приведенном выше коде для назначения локальной переменной. Если одной и той же локальной переменной присваивается значение несколько раз с помощью нескольких newвызовов, она просто инициализирует данные поверх старого значения - она не выделяет больше пространства стека каждый раз. initobj: Использует уже выделенное место хранения и просто стирает данные. Это используется для всех наших вызовов конструктора без параметров, включая те, которые присваиваются локальной переменной. Для вызова метода эффективно вводится промежуточная локальная переменная ,и ее значение стираетсяinitobj. |
|||
86
Кирпич
16.01.21
✎
15:17
|
(85) Ну так могут структуры выделятся в куче или нет?
|
|||
87
Serginio1
16.01.21
✎
15:18
|
(85) >> для конструкторов value типов применяется несколько инциализаторов в заваисмости где память выделяется
Вернее выделение памяти на стеке и инциализация передаваемыми параметрами или обнуление памяти |
|||
88
Serginio1
16.01.21
✎
15:19
|
(86) Как структуры нет, как объект да. Но это уже отбоксенные структры приведенные к object
|
|||
89
Serginio1
16.01.21
✎
15:20
|
88+ я уже ссылки давал. Это азы
https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/types/boxing-and-unboxing |
|||
90
Кирпич
16.01.21
✎
15:21
|
(88) Не один ли хрен отбоксенные они или нет. Они структуры и они не на стеке.
|
|||
91
Serginio1
16.01.21
✎
15:25
|
(90) Большая. Это уже объект. У него есть поле со ссылкой на type (vmt).
По сути это уже другой тип, просто он приводится к value типу автоматически. |
|||
92
Serginio1
16.01.21
✎
15:29
|
91 верее не автоматически а явное привидение (int) .
Автоматически он к боксенному объекту приводится |
|||
93
Кирпич
16.01.21
✎
15:31
|
(91) А по мне так никакой разницы. Мне пофигу что там .NET внутри с моей структурой тварит. Пускай пакует во что хочет. Я пишу через точку и всё. А она в куче.
|
|||
94
Serginio1
16.01.21
✎
15:44
|
(93) Тебе пофигу. В Java тоже так посчитали. Но у них int и боксенный Integer
https://habr.com/ru/post/104231/ Так, заменив один int на Integer, можно сэкономить около 40% используемой памяти. Value типы нужны прежде всего для скорости при уменьшении нагрузки на сборщик мусора. Все зависит от количества таких объектов. Выбор между классом и структурой https://docs.microsoft.com/ru-ru/dotnet/standard/design-guidelines/choosing-between-class-and-struct Если тебя скорость не интересует. То идеальным выбором конечно будет класс. Про боксинг. Нужно не забывать отбоксить. interface IBankAccount { void Add(int amount); } struct BankAccount : IBankAccount { int value; public BankAccount(int value) => this.value = value; void IBankAccount.Add(int amount) => value += amount; public void Add(int amount) => value += amount; public void Print() => Console.WriteLine($"Value: {value}"); } BankAccount ba = new BankAccount(100); ba.Add(50); ba.Print(); IBankAccount iba = ba; iba.Add(50); ba.Print(); This piece of code will probably not print out what you might expect... The output is as follows: Value: 150 Value: 150 Нужно обратно скопировать данные ba=(BankAccount)iba; ba.Print(); тогда получим 200 |
|||
95
Ненавижу 1С
гуру
16.01.21
✎
16:18
|
Интересно автор поста вкуривает разницу между struct и class в c# и c++?
|
|||
96
Кирпич
16.01.21
✎
16:22
|
(94) Да я не собираюсь нигде структуры использовать. Я на C# не пишу пока.
Интересно, а как такая фигня работает? Получается, в xxx() автоматом боксится в объект и возвращает ссылку на него.
|
|||
97
Ненавижу 1С
гуру
16.01.21
✎
16:34
|
(96) так нельзя:
static ref XXX xxx() { XXX r; return ref r; } Нельзя передать ссылку на локальную переменную за пределы ее существования |
|||
98
Кирпич
16.01.21
✎
16:36
|
(97) Мне можно. У меня работает.
|
|||
99
Serginio1
16.01.21
✎
16:44
|
(96) Нет не боксится. Это аналог ref return и параметров передаваемых через out ref in
https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/builtin-types/struct#ref-struct Начиная с C# 7.2 в объявлении типа структуры можно использовать модификатор ref. Экземпляры типа структуры ref выделяются в стеке и не могут временно перейти в управляемую кучу. Для этого компилятор ограничивает использование типов структуры ref следующим образом: Структура ref не может быть типом элемента массива. Структура ref не может быть объявленным типом поля класса или структурой, отличной отref. Структура ref не может реализовывать интерфейсы. Структура ref не может быть упакована в System.ValueType или System.Object. Структура ref не может быть аргументом типа. Переменная структуры ref не может быть зафиксирована лямбда-выражением или локальной функцией. Переменную структуры ref нельзя использовать в методе async. Однако переменные структуры ref можно использовать в синхронных методах, например в тех, которые возвращают Task или Task<TResult>. Переменную структуры ref нельзя использовать в итераторах. |
|||
100
Serginio1
16.01.21
✎
16:45
|
||||
101
Serginio1
16.01.21
✎
16:46
|
||||
102
Serginio1
16.01.21
✎
16:48
|
Ну и передача параметров по ссылке in,ref,out
https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/in-parameter-modifier |
|||
103
Ненавижу 1С
гуру
16.01.21
✎
16:49
|
(98) Ошибка CS8168 Невозможно вернуть по ссылке локальный "r", так как это не локальная переменная ref ConsoleApp10 C:\Users\User\source\repos\ConsoleApp10\ConsoleApp10\Program.cs 15
|
|||
104
Кирпич
16.01.21
✎
16:54
|
(102) Так а как можно вернуть ссылку на стековую переменную. Это же глюк. Получается боксится
|
|||
105
Кирпич
16.01.21
✎
16:54
|
(103) Чота не правильно написал наверное
|
|||
106
Кирпич
16.01.21
✎
16:55
|
или С# старый
|
|||
107
Ненавижу 1С
гуру
16.01.21
✎
16:57
|
(105) я копировал, а не писал. Шарп новый
|
|||
108
Serginio1
16.01.21
✎
16:58
|
(103) ref struct только для .Net Standard 2.1 .То есть только для Core. Для .Net Framework не доступен.
|
|||
109
Serginio1
16.01.21
✎
16:59
|
||||
110
Кирпич
16.01.21
✎
17:00
|
(103) Извини, братан. Я просто здесь пробую. Хрен знает чо там за C# Ж))
https://www.onlinegdb.com/online_csharp_compiler |
|||
111
Кирпич
16.01.21
✎
17:04
|
(108) Так ссылка на что здесь возвращается? На стековую переменную или таки создается копия этой переменной в куче и уже на нее возвращется ссылка?
|
|||
112
Кирпич
16.01.21
✎
17:04
|
А ну щас несколько раз вызову
|
|||
113
Serginio1
16.01.21
✎
17:07
|
(111) А как ты думаешь? Что такое передача по ссылке?
ref, out, in Method(ref int param); Для проверки присвой разным переменным и измени |
|||
114
Serginio1
16.01.21
✎
17:08
|
и посмотри какое значение в реальном объекте
|
|||
115
Ненавижу 1С
гуру
16.01.21
✎
17:09
|
(110) это не настоящий: Mono 5.10.1.20 (tarball Thu Mar 29 10:48:35 UTC 2018)
|
|||
116
Кирпич
16.01.21
✎
17:10
|
(115) Ааааа. Так может это просто баг у них такой
|
|||
117
Кирпич
16.01.21
✎
17:12
|
(114) Я знаю что такое по ссылке. Меня смущает, что ссылка на стековую переменную, которая станет мусором при выходе из xxx()
|
|||
118
Serginio1
16.01.21
✎
17:12
|
(115) Попробуй на .Net 5
|
|||
119
Ненавижу 1С
гуру
16.01.21
✎
17:16
|
(118) я и попробовал на нем:
static ref XXX xxx() { XXX r; return ref r; //<<вот так нельзя локальную переменную вернуть CS8168 } |
|||
120
Кирпич
16.01.21
✎
17:18
|
Интересно это баг в Mono или у них там реально боксит
|
|||
121
Serginio1
16.01.21
✎
18:03
|
https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/classes-and-structs/ref-returns
Для классса прокатывает public class TestRef { int i; public ref int RefProperty { get { return ref i; } } public ref int GetRefProperty() { return ref i; } } Для struct чеhез Span public ref struct TestRefStruct { int i; //var array = new byte[100]; Span<byte> arraySpan;// = new Span<byte>(array); public ref byte RefProperty { get { return ref arraySpan[0]; } } } или расширения https://overcoder.net/q/495043/почему-метод-структуры-c-не-может-вернуть-ссылку-на-поле-а-метод-не-являющийся |
|||
122
Serginio1
16.01.21
✎
18:13
|
Из комментариев
Документация» ( github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/… ) гласит, что «поля структуры экземпляра безопасны для возврата до тех пор, пока получатель безопасен для возврата». Здесь приёмник (параметр foo ) безопасен для возврата (потому что in ), поэтому, кажется, работает как задумано. В то время как первый случай покрыт "this", небезопасно возвращаться из членов структуры ". |
|||
123
Кирпич
17.01.21
✎
08:48
|
Можно структуру в массив запихнуть.
Получается почти как в Mono
|
|||
124
Гений 1С
гуру
17.01.21
✎
09:08
|
Все бы решилось если бы в C# были бы генераторы статического кода, то бишь макросы, как в Си, было бы намного красивее и без извращений:
MULTICOND Cond1 {struct_A r;} Cond2 {struct_B r;}) GENERAL { r.field1 = "aга"; r.field2 = false; } |
|||
125
Кирпич
17.01.21
✎
09:15
|
(124) А почему нельзя просто функцию написать и копипастить её вызов?
|
|||
126
Ненавижу 1С
гуру
17.01.21
✎
10:37
|
(124) макросы это зло
Генераторы кода есть |
|||
127
Гений 1С
гуру
17.01.21
✎
10:46
|
(126) зло не зло, а тут красивее через генераторы кода (макросы).
(125) потому что типы разные. |
|||
128
Ненавижу 1С
гуру
17.01.21
✎
10:53
|
(127) правильнее через интерфейсы
|
|||
129
Конструктор1С
17.01.21
✎
10:53
|
||||
130
Конструктор1С
17.01.21
✎
10:55
|
||||
131
Ненавижу 1С
гуру
17.01.21
✎
10:57
|
(127) нужна статья про кризис-айти в виде отсутствия макросов в шарпе
|
|||
132
Кирпич
17.01.21
✎
11:02
|
(127) "типы разные"
ну ты тип как параметр тоже используй |
|||
133
Гений 1С
гуру
17.01.21
✎
11:09
|
(132) нельзя, язык не поддерживает
|
|||
134
Ненавижу 1С
гуру
17.01.21
✎
11:11
|
(133) передавать как параметр так себе идея. Но тип Type там есть из коробки
Рано тебе ещё гуру-тесты создавать |
|||
135
Гений 1С
гуру
17.01.21
✎
11:12
|
(134) и как Type поможет?
|
|||
136
Ненавижу 1С
гуру
17.01.21
✎
11:14
|
(135) тебе никак. Забудь. Я кстати за адаптер и интерфейс, а не интроспекцию
|
|||
137
Гений 1С
гуру
17.01.21
✎
11:18
|
(136) вот видишь, макрос проще решает эту проблему
|
|||
138
Кирпич
17.01.21
✎
11:27
|
(137) покажи макрос для С++, который решит такую задачу
|
|||
139
Ненавижу 1С
гуру
17.01.21
✎
11:30
|
(137) не вижу. Костыли это
|
|||
140
Serginio1
17.01.21
✎
11:37
|
(123) Да только XXX[] x = { new XXX() }; это уже объект. Не то
(124) Ты не поверишь, но уже есть Introducing C# Source Generators https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/ https://blog.jetbrains.com/dotnet/2020/11/12/source-generators-in-net-5-with-resharper/ https://github.com/dotnet/roslyn/blob/master/docs/features/source-generators.md |
|||
141
Кирпич
17.01.21
✎
11:39
|
(140) Массив объект? Ну наверное. А структура в массиве не объект же?
|
|||
142
Ненавижу 1С
гуру
17.01.21
✎
11:42
|
(141) массив это точно объект. Класс Array
Структура нет. Мне интересно подсчет таких ссылок тоже используется, чтобы объект раньше времени не финализировался? |
|||
143
Кирпич
17.01.21
✎
11:43
|
Так вот еще можно |
|||
144
Ненавижу 1С
гуру
17.01.21
✎
11:47
|
(143) ты уже проверяешь на тру-компиляторе?
|
|||
145
Кирпич
17.01.21
✎
11:48
|
(144) ага
|
|||
146
Serginio1
17.01.21
✎
11:53
|
(143) new XXX[1] это массив. Он выделяется в куче. С этим проблем нет.
Проблема в структурах выделяемых на стеке. При этом ref держит ссылку которая уже не валидная, из-за перезаписи стека. С объектами такой проблемы нет ибо за объектом следит GC и корректирует ссылки |
|||
147
Serginio1
17.01.21
✎
11:54
|
(141) Суть в том, что если структура в объекте, то она не на стеке! Смотри 146
|
|||
148
Кирпич
17.01.21
✎
11:55
|
(146) Ну как бы это понятно. Я просто показал пример, как создать в куче структуру и получить на неё ссылку.
|
|||
149
Ненавижу 1С
гуру
17.01.21
✎
11:58
|
(147) вопрос. Какая гарантия что объект не уничтожится, если есть ref ссылка на его поле-структуру?
Надо углубиться в то как выглядит внутри ref. |
|||
150
Serginio1
17.01.21
✎
12:12
|
(149)
https://overcoder.net/q/495043/почему-метод-структуры-c-не-может-вернуть-ссылку-на-поле-а-метод-не-являющийся Из комментариев Документация» ( github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/… ) гласит, что «поля структуры экземпляра безопасны для возврата до тех пор, пока получатель безопасен для возврата». Здесь приёмник (параметр foo ) безопасен для возврата (потому что in ), поэтому, кажется, работает как задумано. В то время как первый случай покрыт "this", небезопасно возвращаться из членов структуры ". |
|||
151
Serginio1
17.01.21
✎
12:15
|
150 То есть через расширения мы можежем вернуть ссылку на член структуры
struct Foo { internal int _x; public ref readonly int MemberGetX() => ref _x; // ^^^ // Error CS8170: Struct members cannot return 'this' or other instance members by reference } Это приводит к ошибке. Члены CS8170 Struct не могут возвращать "этот" или другие члены экземпляра по ссылке. Тем не менее, выполнение одной и той же функции с использованием метода расширения не вызывает ошибки: static class FooExtensions { public static ref readonly int ExtensionGetX( this in Foo foo ) { return ref foo._x; } } var f = new Foo(); Console.WriteLine( f.X ); f.GetXRefExtension() = 123; Console.WriteLine( f.X ); // You can also do it without using an extension method, but the caller is required to specify ref: FooExtensions.GetXRef( ref f ) = 999; Console.WriteLine( f.X ); /* Output: * 0 * 123 * 999 */ То есть виден контекст и ref работает только на вызывающем стеке |
|||
152
Serginio1
17.01.21
✎
14:19
|
140 + обсуждение и примеры
Introducing C# Source Generators http://rsdn.org/forum/dotnet/7719189.flat |
|||
153
PR
17.01.21
✎
21:32
|
Природа очистилась настолько, что с первой страницы ушли почти все темы Гени
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |