Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

Где найти старый компилятор для C# 4.0

821  1 2 3 все
AlexNek патриот15.03.19 14:53
AlexNek
15.03.19 14:53 
Последний раз изменено 15.03.19 14:59 (AlexNek)

где найти старый компилятор для C# 4.0 желательно онлайн. Просто интересно для проверки closure. В старом по идее не должно быть автовключения строки 13

https://paiza.io/projects/e/MSCBn5zG7GL-FfyOJquZMg?theme=t...

Все что перепробовал добавляют и получается "правильный" вывод.

#1 
MrSanders старожил15.03.19 16:37
NEW 15.03.19 16:37 
в ответ AlexNek 15.03.19 14:53

Исключительно для расширения кругозора - а почему присваивание
int tmp = i;

сделает код "правильным"?

#2 
AlexNek патриот15.03.19 16:42
AlexNek
NEW 15.03.19 16:42 
в ответ MrSanders 15.03.19 16:37, Последний раз изменено 15.03.19 16:44 (AlexNek)

здесь

https://habr.com/en/post/141270/

вроде понятно описано, но в IL не вижу этого. Тоже хочу разобраться.


ну и присваивание немного другое должно быть. Я просто мои тесты не убрал полностью что бы идея был понятна.

#3 
AlexNek патриот15.03.19 16:51
AlexNek
NEW 15.03.19 16:51 
в ответ MrSanders 15.03.19 16:37

вот что генерится

List<Action> actionList = new List<Action>();
foreach (int num in Enumerable.Range(0, 10))
{
        int i = num;
        actionList.Add((Action) (() => Console.WriteLine(i)));
}
foreach (Action action in actionList)
        action();
#4 
Murr патриот15.03.19 17:23
Murr
NEW 15.03.19 17:23 
в ответ AlexNek 15.03.19 14:53
где найти старый компилятор для C# 4.0 желательно онлайн.

-----

С какой версией студии он шел? У меня вроде 2005 самая старая из проинсталленых... остальное надо рыть в дистрибутивах.

#5 
AlexNek патриот15.03.19 17:43
AlexNek
NEW 15.03.19 17:43 
в ответ Murr 15.03.19 17:23, Последний раз изменено 15.03.19 17:47 (AlexNek)

до 2010 включительно

https://www.tutorialsteacher.com/csharp/csharp-version-his...

можешь код компильнуть что по ссылке на 2005 или 2010, что будет в результате? Если 10,10,... то интересно экзешник поиметь и IL глянуть. А то новые декомпиляторы всю картину "портят"

Только это совершенно неважно, если есть какие то проблемы то не нужно.

#6 
AlexNek патриот15.03.19 19:04
AlexNek
NEW 15.03.19 19:04 
в ответ MrSanders 15.03.19 16:37

Вроде кажется дошло, поправьте если неправильно.

Для использования локальных переменных в лямбде/анонимной функции делается как бы снимок всех требуемых переменных в специальном closure class который решили назвать DisplayClass

https://stackoverflow.com/questions/16401860/what-does-dis...

Если внутрь цикла вставить ненужный оператор присваивания, то компилятор создает closure class каждый раз внутри цикла и делает снимок. Без этого оператора closure class создается вне цикла и также делается снимок внутри цикла. То бишь имеем в одном случае 1 экземпляр с 10 присваиваниями в цикле , а в другом случае 10 экземпляров с одним присваиванием. closure class создается в месте "минимальной видимости" переменных.

for (int i = 0; i < 10; i++)
{
     int tmp = i;
     Action action = delegate() { Console.WriteLine(tmp); };
     actions.Add(action);
}
#7 
dymanoid местный житель15.03.19 19:21
dymanoid
NEW 15.03.19 19:21 
в ответ AlexNek 15.03.19 14:53

Не надо его нигде искать. Он на компе есть уже - у каждого.

Открываем cmd.exe и пишем:

C:\Windows\Microsoft.NET\Framework\v3.5\csc /out:C:\v4.exe с:\path_to\Program.cs

А потом пишем:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc /out:C:\v5.exe с:\path_to\Program.cs

Затем открываем любым декомпилятором v4.exe и v5.exe и сравниваем - хоть C#, хоть IL.

#8 
AlexNek патриот15.03.19 20:03
AlexNek
NEW 15.03.19 20:03 
в ответ dymanoid 15.03.19 19:21

Да иногда думать *нихами полезно. Спасибки

Действительно, не обманули, для 4-ки foreach работает "неправильно".


Зато какие интересные побочные эффекты можно получить шок

            var actions = new List<Action>();
            int j = 0;
            int i = 0;
            for (; i < 10; i++)
            {
                //int tmp = i;
                Action action = delegate() { Console.WriteLine(String.Format("{0} - {1}",i, j++)); };
                actions.Add(action);
            }
            int k = 0;
            foreach (var action in actions)
            {
                if (k % 2 == 0)
                {
                    action();
                }
                k++;
            }

10 - 0

10 - 1

10 - 2

10 - 3

10 - 4

#9 
MrSanders старожил15.03.19 20:24
NEW 15.03.19 20:24 
в ответ AlexNek 15.03.19 19:04

Эт феерия какая-то. Т.е. они делали closure (замыкание) по значениям, не ссылкам, но "соптимизировали" его, типа а чо, не меняется же ничего, переменные всё те же, можно новый не создавать. Здорово, память сэкономили, но блин, ведь значения поменялись, а closure у них по значениям, а?

Я так понял что в 5-м микрософт поправил поведение в циклах. А что он сейчас скомпилирует если написать (без цикла)

int i = 1;
actions.Add(() => Console.WriteLine(i));
i = 2;
actions.Add(() => Console.WriteLine(i));

Опять один closure (по значениям!) в котором будет только последняя 2-ка висеть и при отработке Action-ов выдаст нам "2 2"?

#10 
dymanoid местный житель15.03.19 20:38
dymanoid
NEW 15.03.19 20:38 
в ответ MrSanders 15.03.19 20:24, Последний раз изменено 15.03.19 20:39 (dymanoid)

Замыкание в C# делается всегда на переменную, а не на значение.


Прикол был только в версии C# до 4.0 включительно и только с циклом foreach. Связано это с тем, как цикл foreach был специфицирован - во что он развёртывался. Там при развёртывании переменная цикла foreach была задекланирована вовне цикла while. С замыканиями это вообще никак не связано было, просто это проявилось после введения замыканий. В 5 версии изменили спецификацию foreach, а не замыканий.


Не нужно устраивать истерику, не разбираясь в материи.

#11 
  moose старожил15.03.19 20:50
NEW 15.03.19 20:50 
в ответ AlexNek 15.03.19 14:53
Просто интересно для проверки closure.


даже не стрелять - вешать нужно на площадях тех, кто подобной херней балуется, думая, что он при этом умнеет. он болванеет, этого не замечая.


#12 
AlexNek патриот15.03.19 20:58
AlexNek
NEW 15.03.19 20:58 
в ответ MrSanders 15.03.19 20:24

Да результат 2 2

https://paiza.io/projects/62VDITV6xh1IxfbdmnGF2g?language=...

Нефиг подобные лямбды как action пользовать

#13 
MrSanders старожил15.03.19 21:10
NEW 15.03.19 21:10 
в ответ dymanoid 15.03.19 20:38, Последний раз изменено 15.03.19 21:12 (MrSanders)

Давайте всё же как-то общепонятную терминологию использовать. "делается всегда на переменную, а не на значение." это что? Вы хотите сказать что в шарпе closure (не люблю термин "замыкание") хранит не значения, а ссылки на "захваченые" переменные (free variables, определенные снаружи функции), так?

#14 
dymanoid местный житель15.03.19 21:24
dymanoid
NEW 15.03.19 21:24 
в ответ MrSanders 15.03.19 21:10, Последний раз изменено 15.03.19 21:26 (dymanoid)

Я хочу сказать, что в C# замыкание делается на переменную, а не на значение этой переменной в момент создания замыкания.

Так понятнее?

Техническая реализация (ссылка, не ссылка) - это другой вопрос. Для ссылочных типов там, понятно, ссылка хранится. Для значимых типов - значение.


Вот этот пример как раз отлично это иллюстрирует:


int i = 1;
actions.Add(() => Console.WriteLine(i));
i = 2;
actions.Add(() => Console.WriteLine(i));

// 2
// 2
#15 
dymanoid местный житель15.03.19 21:33
dymanoid
NEW 15.03.19 21:33 
в ответ moose 15.03.19 20:50
даже не стрелять - вешать нужно на площадях тех, кто подобной херней балуется, думая, что он при этом умнеет. он болванеет, этого не замечая.

Не согласен. Детальное понимание орудия труда (фич языка программирования) приводит в порядок ум, позволяет решать задачи эффективно и поднимает человека с уровня джуниор-миддл до уровня сениор.

#16 
AlexNek патриот15.03.19 21:35
AlexNek
NEW 15.03.19 21:35 
в ответ moose 15.03.19 20:50
кто подобной херней балуется

А отчего именно для баловства? Никогда не пользовал, не собираюсь и другим постараюсь не дать. Но что бы объяснить, почему это плохо нужно вначале разобраться. А то раз прочел и забыл.

#17 
MrSanders старожил15.03.19 21:35
NEW 15.03.19 21:35 
в ответ AlexNek 15.03.19 20:58, Последний раз изменено 15.03.19 21:54 (MrSanders)

Да, в ставке мелкомягких все малохольные.

var actions = new List<Action>();
int i = 1;
actions.Add(() => Console.WriteLine(i));
i = 2;
actions.Add(() => Console.WriteLine(i));

var actions2 = new List<Action>();
foreach(int j in Enumerable.Range(1,2)){
  actions2.Add(() => Console.WriteLine(j));
}
Console.WriteLine("1:");
foreach (var action in actions){ action();}
Console.WriteLine("2:");
foreach (var action in actions2) { action();}

Радостно выдаёт (поправил, надо было копировать вывод а не перенабирать :), цикл выдаст "1 2", два вызова Add с изменением в промежутке i - "2 2")

1:
2
2
2:
1
2

От это я понимаю, исправили поведение foreach, теперь всё стало ясно и понятно. Уж лучше как в яве, запретить использовать переменные из scope, только константы (final).

#18 
MrSanders старожил15.03.19 21:51
NEW 15.03.19 21:51 
в ответ dymanoid 15.03.19 21:24
Я хочу сказать, что в C# замыкание делается на переменную, а не на значение этой переменной в момент создания замыкания.
Так понятнее?

вроде бы стало понятнее, т.е. "замыкание со ссылками", т.е.

int i = 1;
actions.Add(() => Console.WriteLine(i));
i = 2;
// печатаем

выдаст нам не 1 а 2 (хотя не ссответствует коду Closure из статьи на хабре).

Но тут вы меня опять смутили:

Для ссылочных типов там, понятно, ссылка хранится. Для значимых типов - значение.

Это как? Ссылка, хранимая в переменной "x" ссылочного типа и есть её значение. "замыкание со ссылками" будет хранить ссылку на переменную "x" а не ссылку, хранившуюся в "x" в момент создания closure. Получается в моём примере выше, шарп должен выдать 1, ведь при создании closure он соханил в нём для значимого типа его значение "1"?

Вот этот пример как раз отлично это иллюстрирует:

Не совсем отлично. Тут или шарп создал одно-единственное closure для обеих лямбд (вторая экшен это та же первая), и при инициализации для 2-го action переписал значение i (замыкание со значениями), или он создал два closure но со ссылками на i (замыкание со ссылками).

#19 
AlexNek патриот15.03.19 23:35
AlexNek
NEW 15.03.19 23:35 
в ответ MrSanders 15.03.19 21:51
Тут или шарп...

В результате эксперимента+ILSPY получилось следующее

  • Closure создается для каждой функции.
  • Action создается для каждой лямбды
  • переменные создаются которые нужны
  • перед созданием делегата вызывается Closure.j = 20; - это я просто добавил для теста

IL_0042: ldc.i4.s 20 // 0x14

IL_0044: stfld int32 ClosureTest.Program/'<>c__DisplayClass0_0'::j

#20 
dymanoid местный житель16.03.19 00:02
dymanoid
NEW 16.03.19 00:02 
в ответ MrSanders 15.03.19 21:51

Не хочу азы объяснять. Если интересно - читайте разницу между ссылочными типами и значимыми в C#.

На абстрактные философствования отвечать не буду.

foreach исправили отлично, кто знает язык, тот будет понимать. В первом случае переменная i одна и та же для обоих замыканий, поэтому "2 2" логично. Во тором случае, переменная хоть и называется одинаково, но в каждой итерации цикла она разная, поэтому "1 2". Всё прекрасно и логично.

Кто не согласен - можно идти лесом, а не выпендриваться про "мелкомягких". C# - один из самых красивых и логичных мультипарадигменных языков на сегодняшний день. В отличие от всяких жаб и плюсов.

#21 
MrSanders старожил16.03.19 10:25
NEW 16.03.19 10:25 
в ответ dymanoid 16.03.19 00:02
Не хочу азы объяснять.

Не хочу или не могу? Есть небольшая разница.

Кто не согласен - можно идти лесом, а не выпендриваться про "мелкомягких".

Какая прелесть. Раз вы тут советы раздавать взялись, я вам тоже посоветую. Прежде чем высказывать сверхважное мнение следует немного разобраться в теме. Прочитать про замыкания и 2 (всего навсего) теоретические возможности захватывать переменные окружения, обычно не сложно. Если бы вы это сделали, то поняли бы в чем разница захватывать ссылки на переменные и значения переменных, а не пели бы про разницу ссылочных и значимых типов в шарпе (стек или куча - неважно). А там, глядишь, и самоуверенности с понтами поубавится.

#22 
MrSanders старожил16.03.19 11:14
NEW 16.03.19 11:14 
в ответ AlexNek 15.03.19 23:35, Последний раз изменено 16.03.19 11:14 (MrSanders)

В общем, получается что в шарпе closure со ссылками. Странное Отважное решение, я, честно говоря, не помню в каком еще языке такое есть. Оно было бы логично если бы и методам параметры по умолчанию по ссылке а не по значению передавались бы. А так в шарпе есть ref (привет функциональному программированию, блин), чего бы им при определении лямбд подобным не пользоваться? Хочешь по значению (без ref), хочешь по ссылке.


Проблема с захватом ссылок а не значений в том, что использование closure и присваивание значений переменным может быть сильно разнесено. Забудешь что у тебя closure была, наприсваиваешь чего переменным и всё, 100 строчками кода позже кто-то вызовет такую сохранённую функцию и порадуется непонятному результату. Удачи в дебаге!


У меня другой вопрос - получается что сейчас поведение лямбд, определённых внутри for и foreach будут отличаться, for может работать с ранее определенной переменной, в foreach надо определять свою переменную цикла.
Можете посмотреть поведение 4-й версии с foreach? Сейчас в foreach нельзя присваивать переменной цикла других значений. (просто написать i = 5; внутри). А до 5-й версии (пока foreach не "исправили") тоже нельзя было, или можно?


#23 
AlexNek патриот16.03.19 12:00
AlexNek
NEW 16.03.19 12:00 
в ответ MrSanders 16.03.19 11:14, Последний раз изменено 16.03.19 12:05 (AlexNek)
В общем, получается что в шарпе closure со ссылками.

Что то я вас не пониманию. Где тут ссылки? closure.i = i; Для меня это как бы indirect usage

https://paiza.io/projects/62VDITV6xh1IxfbdmnGF2g?language=csharp


for может работать с ранее определенной переменной, в foreach надо определять свою переменную цикла.

как раз наоборот. Изменили поведение foreach. Closure теперь определяется не снаружи цикла, а внутри.


Сейчас в foreach нельзя присваивать переменной цикла других значений.

Сорри, это тоже что то не понимаю. Ни раньше ни сейчас в foreach нельзя самому менять переменную цикла. Иначе сам принцип изменится.


#24 
AlexNek патриот16.03.19 12:55
AlexNek
NEW 16.03.19 12:55 
в ответ MrSanders 16.03.19 11:14

Тут вроде еще нормально описано

https://itvdn.com/ru/blog/article/closing-in-csharp

Это же надо еще до подобного использования додуматься.

#25 
MrSanders старожил16.03.19 14:06
NEW 16.03.19 14:06 
в ответ AlexNek 16.03.19 12:00
Что то я вас не пониманию. Где тут ссылки? closure.i = i; Для меня это как бы indirect usage https://paiza.io/projects/62VDITV6xh1IxfbdmnGF2g?language=csharp

Хм. Где в вашем коде использование closure? То что вы свой класс так назвали ничего не значит. Вернитесь к примеру с лямбдами.

как раз наоборот. Изменили поведение foreach. Closure теперь определяется не снаружи цикла, а внутри.

Я имел в виду следующее:

int i = 10;
for(;i<20;i++){...} // можно
int j = 0;
foreach(j in ...) {...} // нельзя
//      ^ - должна быть новая переменная
Сорри, это тоже что то не понимаю. Ни раньше ни сейчас в foreach нельзя самому менять переменную цикла. Иначе сам принцип изменится.

Почему это? в начале каждой итерации переменной присваивается значение из списка. Но что мешает мне в блоке foreach менять значение этой переменной? Код на яве: https://paiza.io/projects/e/W6I0zp-bwEBXCWdBekivdA

int[] values = new int[]{1,2,4,8};
for(int i : values){
  i = i+1; // в шарпе нельзя
  System.out.println(i);
}

Выдаст 2,3,5,9

#26 
dymanoid местный житель16.03.19 15:21
dymanoid
NEW 16.03.19 15:21 
в ответ MrSanders 16.03.19 10:25

Повторяю - в C# замыкания всегда происходят на переменную, а не на значение переменной в момент создания замыкания. Что тут непонятного? Если реально не понятно, то вперёд читать букварь. Спецификацию языка то есть. Техническая реализация в CLR остаётся за скобками, поэтому "ссылка/не ссылка" - вообще никакого значения тут не имеет.

Повыпендриваться "не хочу или не могу" советую перед джуниорами на работе, мне это слушать не интересно.

#27 
AlexNek патриот16.03.19 17:58
AlexNek
NEW 16.03.19 17:58 
в ответ MrSanders 16.03.19 14:06
где в вашем коде использование closure?

Вот

var closure = new Closure();

....

closure.i = i;

var action = new Action(closure.Action);

actions.Add(action);


Можно было оставить DisplayClass, но это тоже ничего не меняет ведь компайлер "разворачивает" лямбду в подобный код.

Понятно, что вы смотрите на это с какой то другой стороны. Но пока не могу догнать с какой.


Я имел в виду следующее:

так вроде никак не получится.


15.8.4 The foreach statement

The foreach statement enumerates the elements of a collection, executing an embedded statement for each

element of the collection.

foreach-statement:

foreach ( type identifier in expression ) embedded-statement

я думал что так


foreach(int j in ...) {j=0; ...}

В С# 7.3 вроде поведение как то изменили, но еще не игрался


Почему это?

Отчего в Яве так не знаю. В шарпе foreach коппайлер "переписывает". Да и стандарт не позволяет The iteration variable corresponds to a read-only local variable https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web...

Вот если тут коммент убрать так даже компилится не будет

https://paiza.io/projects/tEMtl6riuHO1bb1LK97ejQ?language=...

#28 
MrSanders старожил16.03.19 20:03
NEW 16.03.19 20:03 
в ответ AlexNek 16.03.19 17:58
Вот
var closure = new Closure();

тут вы просто создаёте объект вашего класса Closure. К замыканиям отношения не имеющим. Замыкание создаётся компилятором когда вы, например, определяете лямбду () => expression.

ведь компайлер "разворачивает" лямбду в подобный код.

Кто сказал? Автор статьи на хабре? Он не прав. Проверка:

int i = 5;
actions.Add(() => Console.WriteLine(i)); // вот тут возникнет closure содержащее эту лямбду и ссылку на i
i = 50;
actions[0]();

Как по-вашему, что выдаст?

Вот если тут коммент убрать так даже компилится не будет
https://paiza.io/projects/tEMtl6riuHO1bb1LK97ejQ?language=...

Вот это мне и интересно, это так с самого начала было или с 5-й версии, а до нее не было "read-only local variable"? Просто интересно было как именно они поведение foreach поменяли.е

#29 
AlexNek патриот16.03.19 21:45
AlexNek
NEW 16.03.19 21:45 
в ответ MrSanders 16.03.19 20:03
Кто сказал?

Декомпилятор, выложить IL? https://github.com/icsharpcode/ILSpy/releases

Только нужно сказать чтобы все показывать


Как по-вашему, что выдаст?

А не нужно гадать, можно просто глянуть


Просто интересно было как именно они поведение foreach поменяли

Достаточно просто, раньше это было вне цикла

var closure = new Closure();

А потом внутри

#30 
dymanoid местный житель17.03.19 11:40
dymanoid
NEW 17.03.19 11:40 
в ответ AlexNek 16.03.19 21:45

Копаться в коде, сгенерированном компилятором, конечно, очень интересно. Но не стоит объяснять реализацию конкретной фичи языка с помощью этого сгенерированного кода - он сильно зависит от версии компилятора и может запутать. Как раз это и происходит сейчас.


То есть, я бы сказал так. Шаг первый. Объясните человеку фичу языка "на пальцах". Логически - что происходит, какие условия должны выполняться и т.д. Когда фича понята, можно приступать к шагу второму: как это реализовано в "компиляторе версии такой-то". Шаг второй нужен, если есть желание досконально разобраться в материале или нужно писать high-perf код и требуется чёткое понимание, что там компилятор такого нагенерирует.


А то получается, объясняем async/await с помощью сгенерированных IAsyncStateMachine структур - тут 90% гуру и сеньоров будут долго репу чесать, чтобы понять всю эту магию. Не нужно так делать.

#31 
dymanoid местный житель17.03.19 11:51
dymanoid
NEW 17.03.19 11:51 
в ответ MrSanders 16.03.19 20:03, Последний раз изменено 17.03.19 11:56 (dymanoid)

Изменение foreach элементарное, но сильно влияет на замыкания.


До 4.0 включительно, foreach разворачивался так:

foreach (V v in x) embedded-statement
-->
{
    E e = ((C)(x)).GetEnumerator();
    try {
        V v;
        while (e.MoveNext()) {
            v = (V)(T)e.Current;
            embedded-statement
        }
    }
    finally {
        … // Dispose e
    }
}


Начиная с 5.0, foreach разворачивается так:

foreach (V v in x) embedded-statement
-->
{
    E e = ((C)(x)).GetEnumerator();
    try {
        while (e.MoveNext()) {
            V v = (V)(T)e.Current;
            embedded-statement
        }
    }
    finally {
        … // Dispose e
    }
}


Единственная разница - область видимости переменной итерации v. Именно это и влияет на то, что происходит с замыканиями. В первом случае замыкание будет на одну переменную для всех итераций, во втором - множество замыканий на разные переменные в каждой итерации.


При этом сама переменная итерации v была и остаётся read-only во всех версиях языка. Это по спецификации, компилятор это гарантирует. Из кода выше этого не видно, потому что это реализовано не кодом, а компилятором. Если убрать эту проверку из компилятора, то технически переменную итерации можно изменять, код это позволяет.

#32 
AlexNek патриот17.03.19 12:16
AlexNek
NEW 17.03.19 12:16 
в ответ dymanoid 17.03.19 11:40
Но не стоит объяснять реализацию конкретной фичи языка с помощью этого сгенерированного кода - он сильно зависит от версии компилятора и может запутать

безусловно, что зависит, но основной принцип, по идее остается неизменным.

Переменные контекста, все равно нужно как то передать. Переменных может быть много, значит нужен контейнер. При этом есть два шага: создание контейнера и копирование контекста.

Эти два шага и могут отличаться от версии к версии для конкретных применений. Это вы имели в виду под логикой или что то другое? Но вполне возможно, что я еще не все до конца понял.

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


А то получается, объясняем async/await

Наверное нужно тоже тему сделать, чтобы точно до конца все добить. На Ютубе только одно приличное видео нашел пока, но все равно не думаю, что на абсолютно все вопросы смогу сразу ответить.

Это нужно пару лет их пользовать чтобы в "кровь вошло".

#33 
dymanoid местный житель17.03.19 12:45
dymanoid
NEW 17.03.19 12:45 
в ответ AlexNek 17.03.19 12:16

В локальных функциях замыкания технически реализованы по-другому. Но по спецификации - это те же самые замыкания, что и в лямбдах. Именно это я имел в виду. Для понимания концепции необязательно лезть в дебри сгенерированного кода и изучать внутренности CLR.

#34 
AlexNek патриот17.03.19 12:50
AlexNek
NEW 17.03.19 12:50 
в ответ dymanoid 17.03.19 12:45
В локальных функциях

ааа... Я их как-то принципиально игнорирую. Пока во всяком случае. Хорошо это или плохо не-знаю.

Надо будет код глянуть...


Для понимания концепции необязательно лезть в ...

А какой есть еще способ - искать приличное описание?

#35 
MrSanders старожил17.03.19 13:14
NEW 17.03.19 13:14 
в ответ dymanoid 17.03.19 11:51

Спасибо, понял.

#36 
AlexNek патриот17.03.19 13:41
AlexNek
NEW 17.03.19 13:41 
в ответ dymanoid 17.03.19 12:45
В локальных функциях замыкания технически реализованы по-другому

А где есть описание, потому как у меня так получилось.

https://paiza.io/projects/OEtazpJ6NB7St4wW7HxA5Q?language=...

Большой разницы не вижу.


#37 
dymanoid местный житель17.03.19 14:00
dymanoid
NEW 17.03.19 14:00 
в ответ AlexNek 17.03.19 13:41
AlexNek патриот17.03.19 14:08
AlexNek
NEW 17.03.19 14:08 
в ответ dymanoid 17.03.19 14:00

ааа..., так просто локальная функция. А я пробовал как раньше было, только вместо лямбды локальную функцию зафигачил.

попробую как попроще, спасибки.

#39 
AlexNek патриот17.03.19 14:27
AlexNek
NEW 17.03.19 14:27 
в ответ dymanoid 17.03.19 14:00

Да, просто для локальной функции получается по другому.

https://paiza.io/projects/IBYy3C_aqEty-9GayHOupg?language=...

#40 
Murr патриот09.04.19 15:30
Murr
NEW 09.04.19 15:30 
в ответ AlexNek 17.03.19 14:27

Н.П.

Просто попалось на глаза - в настройках Студии вроде можно указать какой версией компилятора (не фремворка, а именно компилятора) она должна пользоваться...

Пока не смотрел, искать по Advantage Build Settings.

#41 
dymanoid местный житель09.04.19 20:46
dymanoid
NEW 09.04.19 20:46 
в ответ Murr 09.04.19 15:30

Это не то. Эта настройка позволяет выбрать, фичи какой версии языка разрешены. Компилятор всегда один и тот же.

#42 
1 2 3 все