5 апреля 2016 в 14:24

Новшества C# 7

На втором дне конференции Build 2016 Dustin Campbell и Mads Torgersen рассказали про новые конструкции в языке C#.
Оригинал презентации на английском можно посмотреть здесь.



В этой статье собран полный обзор новых конструкций языка, некоторые из них уже доступны в Visual Studio 2015 Update 2.

1. Бинарные литералы


На разогрев были представлены бинарные литералы.



Можно отделять нули произвольным количеством подчёркиваний.



2. Локальные функции


Хотите структурировать ваш код в стиле JavaScript? Получайте возможность писать локальные функции!



3. Кортежи (Tuples)


Внимание: доступно прямо сейчас, но с помощью другой конструкции (подробнее на MSDN)

В C# 6 можно использовать:
  Tuple<string,int> GiveMeATuple()
        {
            return Tuple.Create("New York", 7891957);
        }


В С# 7 создан более удобный синтаксис.



Можно давать названия каждой переменной (по умолчанию они называются Item1, Item2).
Переменные в кортежах изменяемы.



4. Новый вывод переменных в строке


Внимание: доступно прямо сейчас в Visual Studio 2015 и Update 1

Выше можно увидеть поддержку конструкции, которая уже доступна в Visual Studio 2015 Update 2.
Теперь можно вставлять переменные прямо в строку.

Console.WriteLine($"Sum: {t.sum}, Count: {t.count}");


5. Сопоставление с образцом (Pattern matching)


Теперь можно использовать разнообразные средства для сопоставления.
Пример ниже показывает объявление переменной в блоке if.



6. Условия и использование объектов в переключателях


Маленькая революция для разработчиков. Теперь switch почти ничем не ограничен.
Можно использовать сопоставления.



Можно определить условия.



7. Возвращение объектов по ссылке


Нужно получить ссылку на объект? Проще некуда.



Обсуждаются варианты добавления следующих функций в перспективе.

Записи


Автоматическое создание простых классов с необходимыми полями.


Создание неизменяемых объектов


@Reeze
карма
64,5
рейтинг 0,1
Самое читаемое Разработка

Комментарии (192)

  • +37
    Какой приятный язык! Вот образец синтаксиса для всех создателей языков программирования (это касается и Rust, и Swift, и Go)
    Сам пишу в основном на C++, но направление, в котором развивается C#, всегда нравилось и продолжает нравиться.
    • +33
      Дажвисты вокруг меня забурчали что все это ненужные фичи и замусоривают код )))))
      • +5
        Бурчат не только джависты. Обычно, когда предлагаешь какую-нибудь удобную фичу (например на форумах isocpp.org), тут же находятся люди, которые пишут: «а вот если взять вот это, вот это и еще вон то, использовать это вот так и вот тут подставить пару костылей, то получится именно то что вы хотите». То что оно получится в 10 раз длиннее и на костылях, их почему-то не волнует.
        • 0
          Я хоть и сам джавист, но полностью с вами согласен. Бурчат, еще как бурчат. Поэтому в нашу уютненькую джаву такие фичи еще не скоро завезут.
          • –2
            Дык можно не ждать, пока завезут. Можно уже сейчас заценить цейлон, после последнего релиза они обещали плугин для идеи добить, хотя он и до этого работал относительно нормально
            • 0
              kotlin/scala?
              • 0
                это всё не то
                • 0
                  и чего же? что есть в ceylon чего нет в scala/kotlin?
                  • 0
                    офигенный слоник-маскот!
                    ну из менее важного: красота, стройность, согласованность имеющихся фич. алсо овеществленные дженерики; простая и мощная система типов; модульность, заточенность под тулинг, низкий порог входа.
                    Такой скала должна была стать, но не стала. А котлин как-то даже неприлично с ними рядом ставить, решив не делать свою стандартную библиотеку он унаследовал все косяки явы, ну кроме разве что синтаксиса более сахарного.
                    Короче, цейлон целенаправлено правит косяки явы (что скала недоделала), не трогая того, что там и так хорошо (что скале не стоило), и делает это с размахом, недоступным котлину.
                    также он развивается он куда быстрее обоих
            • 0
              Кровавый энтерпрайз не допускает таких вольностей =)
              Втаскивать новый язык в существующий проект ради плюшек точно никто не будет. Да и новый начинать скорее всего будут на чем-то стабильном и привычном.
              А дома у себя я могу хоть на чем писать, хоть на шарпе, хоть на всех JVM-совместимых языках сразу, здесь вопросов нет, доступны любые плюшки.
              • 0
                I know that feel, bro :)
                Но цейлон больше всех имеет шансы быть протащенным, тк он сам кровавый энтерпрайз кровавого RedHat, и Гевину Кингу, лиду гибернейта и теперь цейлона, тож кровавости не занимать.
                Насчет стабильности тоже не всё так плохо: сам цейлон, два плугина к двум IDE, мэйвенообразная система модулей и сайт — тут и интероп явно есть — пашет же как-то.
                Спека есть.
          • 0
            Groovy вам в помощь.
            Практически 100% Java-compatible + куча приятных конструкций, которые облегачают написание кода.
        • –2
          Горшочек не вари (с)
      • –6
        у нас тут джавист сел за C#, и сколько же я от него бурчанья услышал, из-за того, что с C# отсутствует синтаксис
        for (Object listElement: list) {
        }мне кажется, это больше двойные стандарты, чем реальный мусор
        • +5
          В подкасте devzen как то было бурчание насчет того что имена методов с заглавной буквы. Из за привычки люди могут не углядеть плюсов.
          • +1
            В чем плюсы?
            • 0
              Погорячился, скорее приравнивают "другое" к минусам
          • 0
            А в каком выпуске было?
        • +15
          Э… чем же его foreach (Object listElement in list) не устроил-то? Он что, ожидал увидеть точно такой же синтаксис в другом языке?..
          • –7
            Тем, что это foreach, и in, а не :. вообще, если уж на то пошло, то, что C#, что Java свой синтаксис унаследовали от C, поэтому for, while, do-while синтаксис у них один.
            • +4
              Ну, если так хочется чтобы был только for и чтоб уж прям C-style:
              for (IEnumerator<object> o = collection.GetEnumerator<object>(); o.MoveNext(); )
              {
              //ur stuff in here
              }
              
      • +1
        Тут Джависты чет приуныли и хотят себе такие же фичи в код. В частности кортежи и новые switch'и, с ними как-то реально удобней будет
        • +2
          А у нас тут джависты истерически смеются над бинарными литералами и символами подчеркивания в них. Хоть что-то в джаве появилось раньше.
        • –2
          switch — это уродливая конструкция, которой в принципе не должно быть в коде.
          расширение оной — плохой шаг в развитии языка.

          кортеж — в целом не плохой вариант, но сильно увеличивает сложность восприятия кода, вот пример кода:
          void DoSomeWith(int x, int y, int z);

          DoSomeWith(target.vector);

          теперь метод с тремя параметрами вызывается как метод с одним параметром — удобненько! *сарказм*
      • 0
        Я бы этих джавистов… Пишу под Android, и в Java меня раздражает многословность, синтаксическая бедность и кривые Generics с кривым выводом типов. Мечтаю, чтобы вместо Java в Android был C#, и можно было писать в несколько раз меньше кода для тех же задач.
        • 0
          Ну там можно воспользоваться другими JVM языками типа Kotlin, Scala, Groovy
        • +3
          Мечтаю, чтобы вместо Java в Android был C#, и можно было писать в несколько раз меньше кода для тех же задач.

          Ваша мечта сбылась — xamarin уже бесплатен :)
      • 0
        А Скалисты, просто улыбаются.
        • +3
          Скалисты, я бы сказал, скалятся.
    • +1
      Подтягивают до F#. Сопоставление не такое компактное конечно…
      • +2
        Какая-то супер компактность и не нужна. Нужна разумная компактность в сочетании с привычным синтаксисом. Чтобы, взглянув на код, любой программист (и не только на C#, но и на C++, Java и т.п.) смог сходу понять, что же тут написано, даже не задумываясь. Мне вот представленный код вполне понятен, хотя я и на C#-то почти не пишу.
        • +5
          Абсолютно не согласен. Нужен удобный для постоянного использования синтаксис, пусть лучше его придётся один раз освоить. От предложенного варианта за три версты разит желанием впихать всё в swich «лишь бы match в язык не добавлять».
          • +1
            К сожалению, они вынуждены балансировать между удобностью-читабельностью и обратной совместимостью. Большинство вариантов удобного синтаксиса являются валидным кодом на С# младших версий.
            • 0
              Добавляем блок match и вуаля — внутри него любые выражения можно наделять нужной семантикой.
              • 0
                И моя супер программа dotnetfiddle.net/My8n4Y сломается.
                • +2
                  Так-же как программа c переменной async, написаной на C# 2
                  Однако это ключевое слово добавили. Refactor->rename наше всё
                  • +2
                    Нет, async и await — это валидные имена переменных в c# dotnetfiddle.net/eQ2mkl
                    • 0
                      Да, async и await контекстно-ключевые слова, согласен, что неудачный пример.
                      Тем не менее, большой беды в этом не вижу.
                      Такой код можно отмигрировать автоматизированно.
                      • +1
                        Вы не видите, а команды С# и .NET Framework делают всё, чтобы не ломать ваш код и при этом развивать язык и фреймворк.

                        Если вам интересна эта тема, советую посмотреть трансляции API Review и почитать обсуждения Proposal в репозитории Roslyn.
                        • +2
                          Я читал Proposal. Другое дело, что я с такими доводами несогласен, поэтому я ушёл с C#. Мне кажется, что при качественных изменениях некоторая потери обратной совместимости неизбежна.
                      • 0
                        К вопросу об автоматической миграции: работал я как-то в компании, которая 30 лет писала банковский софт на самопальном процедурном языке с макросами.
                        Потом они этот код конвертировали в C#, завернули в виртуалку и начали поставлять клиентам. Там название части классов были из оригинального кода (на голландском и с сокращениями), а имплементации макросов были названы рандомными строками.
                        При этом кода там было очень много. Решарпер на этом вешался и валил студию, MSBuild собрать солюшн не мог, приходилось городить многошаговые скрипты сборки. Посмотрел бы я как они автоматически исправлялют несовместимости компилятора в таком коде. Тем более, что все фиксы там делались в конверторе, который тупо регенерил весь солюшн заново.
                        Такой вот ад программиста. Это, конечно, экстремальный случай, но и без него в мире существует много софта, рефакторить который — себе дороже.
                        • 0
                          >>Посмотрел бы я как они автоматически исправлялют несовместимости компилятора в таком коде

                          Для такого существует Roslyn. Даже транспилеры можно делать (из шарпа ещё куда).
                          • 0
                            Добавить к багам транслятора ещё и потенциальные баги самодельной тулзы на розлине (стабильной версии которого в те времена не было)? Увы, это очень дорогое и сомнительное удовольствие.
                            При этом переезд с .NET 3.5 на 4 тот проект пережил без особых проблем.
                            • 0
                              >>потенциальные баги самодельной тулзы на розлине
                              Тут уже всё зависит от того, как вы расставите приоритеты.
                              • 0
                                Мне кажется, что приоритетнее иметь компилятор, который не ломает существующий код. Что я и пытаюсь донести в этой ветке. Иначе будет у нас, как в Python мире, где существующий код с 2.7 на 3 не перенести. Никто там автоматической конвертацией не занимается, если этого можно избежать.
                                • 0
                                  У вас просто получается так, что после выпуска первой редакции языка вообще нельзя вводить дополнительные ключевые слова: вдруг у кого-то названа переменная таким именем. Хотя, корневое слово, без префикса/суффикса это скорее моветон, чем общепринятая практика.
                                  p.s. для автосгенерённых исходников специально существует префикс "@", который явно указывает компилятору о том, что лексему следует обрабатывать как идентификатор. Я так делаю в расширениях:
                                  internal static void foo<T>(this T @this) 

                                  (и, разумеется, когда пишу генераторы кода)
                                  • 0
                                    Там выше пример с функцией match. Имя, как имя.
                                    Сколько новых ключевых слов было добавлено в C# с первой версии и сколько из них ломали компиляцию существующего кода? Вот про это я и говорю. Добавлять можно, но трудно.
                                    Поведение старого кода новым компилятором, кстати, ломали несколько раз, но это были очень редкие и трудновоспроизводимые ситуации. Хотя, все помнят редизайн foreach, там получилось так себе.
                                    Вы мне доказываете, что проблемы можно решить, а я вам говорю, что дизайн-команда языка пытается их избежать. Отсюда и неловкий синтаксис у паттерн матчинга.
                                    • 0
                                      Выше я уже писал, что корневые слова без префиксов/суффиксов это плохая практика. Достаточно написать _match, и это уже значительно снизит шансы на дальнейшие коллизии. Ту-же ошибку допустил автор freetype2, и теперь приходится переопределять «generic» для того, чтобы собрать проект.
                                      p.s. и все-таки что вы предлагаете: не вводить новых ключевых слов?
                                      • 0
                                        Конечно можно. Вы у себя в коде будете использовать все эти l_ и m_, и этим самым решите для себя проблему. А команда Roslyn не хочет рефакторить свой код и выслушивать претензии коллег из EF. Вот и осторожничают.
                                        • 0
                                          А можно комментарии к этим ссылкам? Глянул, ничего преступного не нашел.
                                          • 0
                                            идентификаторы: корневые слова без префиксов.
                                          • 0

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

                                            • 0
                                              Эм, я подумал речь о существующих ключевых словах. Тогда так:
                                              Во-первых никакого `builder` не собираются вводить, насколько мне известно.
                                              Во-вторых ЛЮБОЕ изменение языка приводит к пересмотру существующего кода. Эволюционное развитие с обратной совместимостью это хорошо, но не когда оно тормозит разработку.

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

                                              Минимально — 2 галки, одни вводят только новый синтаксис, который не ломает старый (null-propagation например), и вторые — которые вводят новые ключевые слова и т.п.

                                              Максимально — каждая фича ставится отдельной галкой. Нужны async/await — одна галка, нужно еще что-то — другая галка. Это немного усложнит csc, нужно будет передавать примененные параметры, и генерировать код основываясь не на версии, а на активированных фичах. Но тут уж либо одно, либо другое :) Либо обратная совместимость за счет компилятора, либо за счет потери развития языка (топчемся на месте => все хорошо, ничего не ломается), либо не имеет обратной совместимости вообще. Классическая дилемма «выбирайте 2 из 3».
                                              • 0

                                                Я понимаю, это достаточно скучный тред, я в нём повторяю одно и тоже, однако меня не слышат. Команда C# не ломает компиляцию существующего кода, в том числе этим обусловлен такой корявый синтаксис в некоторых местах.


                                                Вариантов развивать язык — куча, но конкретная команда выбрала именно такую стратегию для C#. Вот и всё. Если вы готовы выключать функции флажками, добавлять префиксы к именам, заниматься рефакторингами после смены компилятора — хорошо, с вами никто не спорит, но C# дизайнится с оглядкой на другие вещи. Иными словами: я начал тред объяснив почему сделано именно так, а мне все бросились объяснять, что они сделали бы иначе.


                                                P.S. Пример с builder достаточно простой, я не знаю, зачем вы мне объясняете, что его не будут вводить.

                                                • 0
                                                  Ну, нельзя их за это упрекать, да и я не спец в разработке языка, вдруг там есть куча нюансов, о которых я даже не подозреваю. Но то, что синтаксис получается корявенький расстраивает. Ладно, не хотите добавлять новый кейворд match, сделайте у него две формы: старую и новую, соответственно старая имеет текущий вид, а новая уже больше похожую на раст какой-нибудь. Компилятор легко мог бы выбирать между двумя формами. Например убрать ключевое слово case, если оно есть — то это старая форма, если нет — то новая. Никаких новых ключевых слов, полная обратная совместимость. Почему бы нет? Я особых минусов такого подхода не вижу…
                                                  • 0

                                                    Верно, тонкостей много. Возьмём тот же пример с rust-подобным синтаксисом. Как я понял, Вы говорите про что-то такое:


                                                    switch(c) 
                                                    {
                                                        x => Console.WriteLine(x);
                                                    }

                                                    Такой вариант обсуждался и его не приняли из-за того, что сейчас из case можно вернуть значение:


                                                    string Foo(bool x) {
                                                         switch (x) {
                                                            case true : return "hello";
                                                            case false: return "hi";
                                                        }
                                                    }

                                                    в данном случае return возвращает значение из метода Foo, в котором объявлена конструкция switch.


                                                    С другой стороны выражение x => return 10; похоже на объявление лямбда выражения, где return возвращает из этого выражения, а не из метода, в котором объявлено это выражение.


                                                    Если взглянуть на rust-подобную конструкцию:


                                                    string Foo(bool x) {
                                                       switch(x){
                                                           true => return "hello";
                                                           false => return "hi";
                                                       }
                                                    }

                                                    семантически похоже на то, что мы возвращаем не из Foo, а из ветви case.

                                                    • 0
                                                      И как этот вопрос решили в новом синтаксисе? Вроде все те же проблемы остаются.
                                                      • +1

                                                        Так и решили: нет нового синтаксиса — нет проблем :)


                                                        Давайте ещё раз попробую.


                                                        Раньше была контрукция case something: return;. Эта конструкция возвращала из метода, в котором объявлен switch, а не из ветви case.


                                                        Так же раньше была конструкция:


                                                        void Foo()
                                                        {
                                                            Func<int, int> name = x => {return x;}; // возвращаем не из Foo, а из x
                                                            x(); // после return остаёмся в Foo
                                                            return; // а теперь возвращаем из Foo
                                                        }

                                                        теперь если ввести конструкцию


                                                        int Foo(int x){
                                                            switch (x){
                                                                something => return x;
                                                            }
                                                        }

                                                        она выглядит так, будто мы возвращаем из блока case (который тут неявный), а не из Foo.
                                                        Выходит, схожий синтаксис, а поведение отличается. В одном случае выражение не управляет control flow родителя, а во втором случае управляет. Consistency языка нарушается. Вот и решили отказаться в пользу уже существующего синтаксиса.


                                                        Я не говорю, что это самая лучшая аргументация, и просто объясняю, чем руководствовались в данном случае.

          • 0
            Не вижу ничего плохого в том чтобы добавить ключевое слово match; хотя если можно добавить новую функциональность в switch, сохранив совмесимость (и сделав старую функциональность частным случаем новой) — то в чем смысл введения нового ключевого слова?
            Нет, я о другом.
            // Pattern matching with multiple alternatives on the same line.
            let filter123 x =
            match x with
            | 1 | 2 | 3 -> printfn "Found 1, 2, or 3!"
            | a -> printfn "%d" a

            Взять хотя-бы вертикальную черту — в традиционных, старых добрых си-подобных языках это «битовое или». Что с этим делать в C#???
            Скобок у функций нет, что слегка рвет шаблоны восприятия; сам по себе блок не обрамлен фигурными скобками; конечно, всему можно научиться, но если подсознание уже настроено на определенную систму обозначений, почему бы не использовать ее?
            • 0
              Да, что-то такое на новом C# выглядит жутковато

              switch (x)
              {
                  case int i when i == 1 || i == 2 || i == 3:
                      WriteLine("Found 1, 2, or 3!");
                      break;
                  case var a:
                      WriteLine($"{a}");
                      break;
              };
              
              

              • –1
                Можно присыпать это сахаром, выглядит не так плохо:
                var x = 10;

                var y = x match
                (
                case int i when i >= 1 || i
              • 0
                Э… а зачем так сложно? Вот так что, больше работать не будет?
                switch (x) {
                  case 1:
                  case 2:
                  case 3:
                        WriteLine("Found 1, 2, or 3!");
                        break;
                  default:
                        WriteLine(x);
                        break;
                };
                
                • 0
                  Это простой случай который будет работать потому что switch expression один из sbyte, byte, short, ushort, int, uint, long, ulong, char, string, enum-type, и case constant-expression можно неявно привести к одному из этих типов, в случае с when мы можем вычислить выражение, как в примере x.Any(), что сделать в случае case нельзя.
                • 0
                  Да, всё верно, я показал синтаксис when, а case 1: case 2: и раньше работало.
      • 0
        все что появляется в С# было очень давно в F# и они оттуда берут все
    • –2
      Справедливости ради, все эти конструкции присутствуют в Swift с первой версии.
      • +1
        А так же в свифте нет много того, что есть в C#.
        • +2
          Это как-то противоречит моему комментарию? Я говорю о конкретных фичах, описанных автором, и не спорю о C# в целом.
      • +10
        Только маленький нюанс — Swift вышел в через 13 лет после C#.
        • +3
          Не нужно воспринимать мой комментарий в вакууме.Он был ответом на конкретное утверждение «Вот образец синтаксиса для всех создателей языков программирования (это касается и Rust, и Swift, и Go)». В данном случае, описанные фичи в свифте появились первыми. При этом естественно, C# — крутой язык, и целиком сравнивать его со Swift я не собирался.
          • 0
            Ну как бы используемый Objective C показывает отлично что было бы, если ребята не стали основываться на существующих решениях или выпустили бы Swift 13 лет назад.
    • +1
      Для меня как PHP разработчика это просто невозможно прочитать)))) Пойду учить C#)
    • НЛО прилетело и опубликовало эту надпись здесь
  • +12
    «Теперь можно вставлять переменные прямо в строку.

    Console.WriteLine($»Sum: {t.sum}, Count: {t.count}");"

    Разве этого не было в C#6?

    «Возвращение объектов по ссылке» — разве сейчас работая с объектами мы не работаем с ссылками на них или тут что-то другое имеется ввиду?
    • +1
      второе — это указаель на указатель. MyClass** instance. Чтобы можно было менять указатель на объект в методе

      void Method(ref Class obj)
      {
      obj = null;
      }

      var inst = new Class();
      Method(ref inst);
      Assert.Equals(null, inst);

      • +3
        а разве там не ключевым моментом является ref в возвращаемом типе? и то о чем вы пишете (разименовывание ссылки) разве не было доступно всегда?)
    • +3
      Помимо этого, насколько я понимаю, по ссылке теперь можно хранить и возвращать структуры, с которыми мы раньше не могли так широко работать по ссылке.
      • +1
        всеравно, наверно, не самое рекомендованое манипулирование структурами, там же всеравно упаковка/распаковка стоит за всем этим.
        • +1
          Но зато не будет лишнего копирования! Да и распаковки не будет, если локальная переменная имеет ссылочный тип (насколько я понимаю, такое теперь тоже должно стать возможным).
    • +2
      «Возвращение объектов по ссылке» — разве сейчас работая с объектами мы не работаем с ссылками на них или тут что-то другое имеется ввиду?

      Это сделано по предложению человека в Rosylin'е. Поподробнее можете по ссылке почитать, там на целые страницы расписано в мельчайших деталях все подробности и причины такой фичи.
      Исходная формулировка:
      Interestingly, that support in the CLR is actually a more general mechanism for passing around safe references to heap memory and stack locations; that could be used to implement support for ref return values and ref locals, but C# historically has not provided any mechanism for doing this in safe code. Instead, developers that want to pass around structured blocks of memory are often forced to do so with pointers to pinned memory, which is both unsafe and often inefficient.
      • 0
        Спасибо за ссылку, значит кто-то в комментариях выше был прав, что в основном это нужно для более удобной работы со структурами
  • 0
    Кортежи, pattern matching, улучшенный switch — C# приближается к Эрлангу! Обязательно надо проверить, что получилось.
  • +5
    За автоматическое создание простых классов держу крестик.
    • 0

      Вопрос в том, насколько хорошо вам там сделают Equals и GetHashCode.

  • +9
    Кортежи немного ущербны, надеюсь, добавят деструктурирование при присваивании

    var tuple = (1, 2);
    var (a, b) = tuple;

    Console.WriteLine($«a={a}, b={b}»);
    // a=1, b=2

    Паттерн-матчинг, надеюсь, будет не только с выводом типов работать. Там деструктурирование тоже не помешало бы.
    • 0
      Ну по ходу это:

      var tuple = (1, 2);
      var (a, b) = tuple;

      эквивалентно этому:

      var (a, b) = (1, 2);

      так почему бы Вашему варианту не работать?)
      • 0
        Это не совсем эквивалентно, наверное я не очень понятно написал.
        Хотелось бы, чтобы а и b могли быть переменными, а не просто именованными полями кортежа.
        • 0
          Радуйтесь, вот тут описано: habrahabr.ru/post/256825
    • 0
      Судя по этим ссылкам (раз, два), это все будет.
  • +3
    Интересно, позволит ли новое получение ссылки объявлять out переменные по месту:

    // Было
    string result;
    if (myMap.TryGetValue(«123», out result)) { Console.WriteLine(result); }

    // Могло бы
    if (myMap.TryGetValue(«123», var out result)) { Console.WriteLine(result); }

    Вообще, не могу придумать сценарий использования возвращения по ссылке.
    • 0
      Этот вариант уже реализован в C# 6
      • +4
        Прошу прощения. Они обещали эту фичу в C#6, но в релиз она не была добавлена — github.com/dotnet/roslyn/issues/254
    • 0
      Вообще, не могу придумать сценарий использования возвращения по ссылке.

      В дизайн-документе есть хороший пример:

      public static ref TValue Choose<TValue>(Func<bool> condition, ref TValue left, ref TValue right)
      {
          return condition() ? ref left : ref right;
      }
      
      • 0
        Кстати да, это, получается, можно теперь вызов метода слева от присваивания писать?

        my.ChangeMe(1, 2, true, «Data») = 123;

        Этак и до Dшного unified function call syntax недалеко.
        • +1
          сильное колдунство, ничего не скажешь
        • 0
          подозреваю, что придется писать:

          ref my.ChangeMe(1, 2, true, «Data») = 123;
          • 0
            Скорее всего. Еще ref плохо совместим с auto property, т.к. можно сделать ref на поле, но нельзя на свойство. Хотя можно, наверное, добавить специальную обработку ссылок на авосвойства в компилятор.
      • +1
        Пример хороший, но я за 5 лет работы на C# ни разу рефом вообще не воспользовался.
        • 0
          Счастливый человек.
  • +7
    Все круто, но то, что в статье названо фразой Pattern Matching, на самом деле просто укороченная запись проверки типа. Настоящее сопоставление с образцом позволяет заглянуть вглубь любой структуры данных и вытащить ее части в качестве локальных переменных. Надеюсь, будут развивать дальше и в одной из следующих версий это всё-таки будет.
    • +3
      Как я понимаю, они собираются именно в C# 7 реализовать полноценное сопоставление с образцом.

      Вот тут github.com/dotnet/roslyn/blob/features/patterns/docs/features/patterns.md можно найти более-менее подробную спецификацию того, что планируется сделать. Если смотреть описываемую в пункте Patterns грамматику, то видно, что в ней рекурсивное сопоставление с образцом описано.

      К тому же среди примеров (см. пункт Arithmetic simplification) есть случай, из которого становится понятно, что будет возможно заглянуть вглубь любой структуры данных и вытащить ее части в качестве локальных переменных.
      • +2
        Да, в proposal'е есть очень много интересных вещей. Если и правда всё реализуют — будет превосходно! Однако пока у меня есть опасение, что такую большую фичу могут отложить до следующей версии, как было в прошлый раз с кратким синтаксисом для конструкторов.
    • +9
      Вытаскивать части структуры и использовать их, как локальные меременные можно:

      image
      • 0
        ААА, супер! Хотет!!!
      • +2
        Но синтаксис извлечения просто ужасен.
        • 0
          Он просто громоздкий.
      • 0

        А вот мне интересно, в примере выше можно использовать as вместо is, в смысле Value as var head?

        • 0
          as — это приведение типа, is это проверка типа. Семантически логичнее is.
  • +2
    Кортежи и локальные функции?
    Наконецто!
    • –1

      Ну локальные функции давно уже были как делегаты и лямбды. Сейчас их просто как обычные функции оформили.

      • +1
        Локальные функции могут чуть больше, чем лямбды и делегаты.
      • 0
        на каждом вызове создавать новый обьект в куче: нет, спасибо
  • 0
    Reeze а какая версия .NET требуется?
    • 0
      Скорее какая сборка компилятора Roslyn. Весь синтаксический сахар теперь пихают туда. Вероятно, что все это появится уже совсем скоро в следующем обновлении VS.
    • +3
      Да, как уже выше написали, это всё фичи компилятора, а не рантайма. Под .NET 4 примеры собираются без проблем.
    • +5
      Visual Studio 15 и __DEMO__ в Conditional compilation symbols и __DEMO_EXPERIMENTAL__ для «match»
      • +1
        Спасибо тебе, мил человек
        • 0
          В блоге Josh'a Varty joshvarty.wordpress.com очень подробно описано как собирать без VS15
      • 0
        Откуда информация? Есть ли полный список того, что включается с этими символами?
        • 0
          Например из этого поста. Эти символы включают флаги для MSBuild. Без них студия будет выводить сообщения об ошибках с подсказками о том, какие ключи нужно добавить.

          Error CS8058
          Feature 'local functions' is experimental and unsupported; use '/features:localFunctions' to enable.
          


          Тут есть список ключей для __DEMO__:

          * Nested local functions extend the language to support declaration of functions in a block scope (use /features:localFunctions)
          * Pattern matching extensions enable many of the benefits of algebraic data types and pattern matching from functional languages (/features:patterns)
          * Ref returns enable functions to return values by reference (/features:refLocalsAndReturns)
          • 0
            А, вот в чем дело. Я перепутал Visual Studio 15 и 2015 Update 2 и удивлялся, почему символы компиляции не работают.
            • 0
              О, да, MSFT даже в своём анонсе шутили:
              At Build 2016 we shared a preview of the next version of Visual Studio, which we call Visual Studio “15” (not to be confused with Visual Studio 2015).

              Думаю, что это, как всегда, временное название.
              • +1
                Это не временное название — а нумерация версий у них такая!

                Visual Studio 2012 = 11.0
                Visual Studio 2013 = 12.0
                Visual Studio 2015 = 14.0

                (куда 13.0 делась — не знаю)
                • 0
                  Вроде бы из-за суеверий про число 13 (MS Office тоже стороной обошёл это число: раз, два).
    • +1
      Сомневаюсь, что эти вещи затронут рантайм. Скорее всего, добавится только синтаксис. Ну а кортежи на уровне сборок будут Tuple.
  • –6
    Добавлю и свои пять копеек: многое из этого уже есть в Scala. :)
  • 0
    Мне были бы интересны какие-то фичи для работы с анонимными типами. Возможность ссылаться на них, использовать без дополнительных танцев с бубном.

    Например, буквально вчера столкнулся с необходимостью создания HashSet'а вида
    new HashSet<?>(items.Select(item => item.Attachment))

    Это строчка из довольно большого куска в LINQ-стиле, где Attachment ранее создан как объект анонимного типа, соответственно, вместо "?" пришлось писать «object».
    • +1
      придётся автоматически выводить через дженерики. По-другому не представляю как
    • +3
      Магия C#

      public static class Ext
      {
      public static HashSet ToHashSet<TSrc, TDest>(this IEnumerable source, Func<TSrc, TDest> selector)
      {
      return new HashSet(source.Select(selector));
      }
      }

      internal class Program
      {
      private static void Main(string[] args)
      {
      var anon = new[]
      {
      new {A = 1, Attachment = new {B = 2}},
      new {A = 1, Attachment = new {B = 3}},
      new {A = 1, Attachment = new {B = 2}}
      };

      var set = anon.ToHashSet(a => a.Attachment);
      }
      }
      • 0
        Что это за non generic `HashSet` у вас? Допустим, это что-то стороннее, но это же не решает проблему автора, вы просто убрали типизированную коллекцию в аналог `HashSet<object>`
        • +2
          У него парсер съел <TDest> просто. И в других местах тоже по-обедал. Код был рабочим и решал проблему автора (до прихода парсера).
          • +1
            Да, верно, странно себя повёл парсер, половину скобок оставил.
            • 0
              Он оставил некорректные «тэги» (те, в которых запятая)
        • +4
          Вот нормально отформатированный код:

          public static class Ext
          {
          	public static HashSet<TDest> ToHashSet<TDest>(this IEnumerable<TDest> source)
          	{
          		return new HashSet<TDest>(source);
          	}
          
          	public static HashSet<TDest> ToHashSet<TSrc, TDest>(this IEnumerable<TSrc> source, Func<TSrc, TDest> selector)
          	{
          		return new HashSet<TDest>(source.Select(selector));
          	}
          }
          	
          internal class Program
          {
          	private static void Main(string[] args)
          	{
          		var anon = new[]
          		{
          			new {A = 1, Attachment = new {B = 2}},
          			new {A = 1, Attachment = new {B = 3}},
          			new {A = 1, Attachment = new {B = 2}}
          		};
          		
          		var set = anon.ToHashSet(a => a.Attachment);
          	}
          }
          
          • 0
            Как? Как вы это сделали? Или с ридонли аккаунтом это невозможно? Я пробовал маркдаун, теги, гуглил — и не нашел.
            • 0
              Скорее всего, при нулевой карме это и правда невозможно. Использовал я тэг <source lang=«cs»></source>

              Вам же могу посоветовать менять < на &lt;
              • +1
                Непонятно, кому хуже делает невозможность пользования разметкой нулевая (и отрицательная) карма. Ну очевидно же, что только читающему! Если человек хочет что-то написать, его не остановить. Зачем так сделано, уму не приложу.
                • +2
                  Для того, чтобы пишущему досталось еще больше минусов. Серьезно — видел однажды два комментария рядом, в первом была ссылка текстом, во втором — картинка. И хотя у обоих комментариев по сути было одинаковое содержание(ссылка, если ее скопировать и открыть — вела на ту самую картинку, которую добавил другой человек чуть позже), но комментарий с текстом был заминусован, а с картинкой — заплюсован.
                • +2
                  Полагаю это сделано для того, чтобы озлобившийся народ не постил картинки нехорошего содержания, в качестве мести сообществу или шутки ради. Хотя, было бы достаточно срезать <img/>.
          • 0
            А так не симпатичнее?
            public static class Ext
            {
                public static HashSet<TDest> ToHashSet<TDest>(this IEnumerable<TDest> source)
                    => new HashSet<TDest>(source);
            
                public static HashSet<TDest> ToHashSet<TSrc, TDest>(this IEnumerable<TSrc> source, Func<TSrc, TDest> selector)
                    => new HashSet<TDest>(source.Select(selector));
            }
            
            internal class Program
            {
                private static void Main(string[] args)
                {
                    var anon = Enumerable.Range(1, 3)
                        .Select(i => new { A = 1, Attachment = new { B = i } });
            
                    var set = anon.ToHashSet(a => a.Attachment);
                }
            }
            
  • +1
    7. Идеальный способ наплодить утечек. Берём List, получаем ref на элемент, прикапываем, меняем List до наступления реаллокации. Без контроля алиасинга будет масса весёлых часов отладки.
    • +1
      Ну да, ещё один способ продлить время жизни кадра стека. Тоже об этом подумал, но в конце концов, выстрелить себе в ногу можно и обычными делегатами.
    • +1
      Время жизни только до выхода из метода же? А вообще ref из листа не сможешь получить потому что индексатор (или метод) должен быть реализован как ref, и сеттер в ref индексаторе должен отсутствовать.

      Вот PR где рассматриваются некоторые моменты github.com/dotnet/roslyn/pull/8030
      • 0
        ref, по идее, будет уже на экземпляр, а не на «элемент массива» (т.к. у нас и массивов то нет в чисто сишном представлении, а только результат работы метода индексирования), посему не будет зависеть от изменений в изначальном контейнере.
        • +1
          int[] и любой вэлью-тип с Вами не согласен. Будет реф на ячейку в массиве.
          • 0
            Мне надо было просто прочитать PR ( -_-)
          • 0
            По идее только у массива и будет так работать, у листа индексатор вернет копию и ref будет на эту копию
            • 0
              Ну, можно же написать свой класс, где индексатор будет тоже возвращать ref…

              Вот тогда-то утечки памяти себя и покажут! :)
              • 0
                Вопрос, как долго сможет жить этот реф? Можно ли его будет положить в поле класса или структуры, можно ли иметь массив рефов, или это может быть только переменная тела метода?

                Собственно, есть ли сейчас опасность утечек от того, что имея массив, мы передаем в какой то метод реф на его элемент?
                • 0
                  реф продлит время жизни обьекта, на который он указывает
                  или даже на кадр стека, если реф на value-type
                  Уничтожится он ровно тогда, когда уничтожится обьект/кадр стека, его содержащий
    • 0
      С Listом так не получится — он не выставляет наружу используемый для хранения массив, только свойство-индексатор.
      • 0
        Это просто пример из головы как можно легко и непринуждённо отстрелить себе ногу по самые гланды. C++ style между прочим.
  • 0
    Ну наконец-то они с синтаксисом кортежей разберутся! Новый switch тоже весьма порадовал.
  • 0
    1. Никому не показались конструкции с сопоставлениями какими-то сложными?
    2. Расширение возможностей работы с ссылками разве не делает код менее безопасным?
  • –1
    в 5 забыли поставить фигурные скобки после if или это еще что-то новое?
    • 0
      deleted
    • +2
      Достаточно давно можно писать конструкции if,else,for,foreach без фигурных скобок.
      Есть некоторые ограничения и не всегда считается хорошей практикой:

      if (foo)
          Bar();
      
      for(int i = 0 i < count; i++)
          Bar(i);
      
      • +2
        мне хочется приводить этот скриншот как хороший пример, к чему может привести использование if без скобок. там же count инкрементится для каждого елемента массива, хотя оно и на той же строке, что и сумма?
    • 0
      Это неудачный скриншот из видео. Там этот код постоянно переписывают, отрываясь на рассказ о конструкциях языка. Большую часть видео код на нём некомпилируемый. Через несколько секунд его перепишут на switch(v) {case int i: ...}
      • 0
        В текущей итерации Roslyn без твиков реестра и прочего в том же духе там тоже далеко не всё скомпиллится. И IntelliSense пока что не заточен под все эти конструкции.
        • 0
          IntelliSense не очень хорошо подхватывает это, но всё, кроме tuples компилируется нормально.
  • +1
    5 пример — что там вообще написано?

    Почему нет фигурных скобок? Без них r.c инкрементируется независимо от проверки if. Так и задумано? Тогда почему пишут на той же строке?
    Что вообще значит
    (v is int i)
    


    Я понимаю, что проверяют v число или нет, но переменная тут причем?

    Хотя… посмотрев следующий пример становится понятно, что если v — число, то оно конвертируется в переменную i численного типа. Ужасно, если честно.
    • 0
      Но если привыкнуть то становится очень удобно, вместо 2 строчек с if и созданием новой переменной имеем одну, но соглашусь, по началу разбираться в таком коде будет тем ещё приключением...
      • 0
        Мне кажется, просто, что там слово as было бы уместнее.
        • 0
          Нет, не уместнее. Все-таки оператор is дает булево выражение, в отличие от as.
          • +3
            Это да, но вот читая код, совершенно не понимаешь его смысла:
            v is int
            

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

            Если написать
            if(v as int i)
            

            то можно прочитать это как попытка приведения v к int переменной и запись результата в i.
            И можно было бы сделать возвращение этим выражением true/false по аналогии со стандартной проверкой на null.

            Основной смысл этого выражение — получение новой переменной с новым типом, а не проверка на тип. Поэтому я считаю, что именно As был бы уместнее.
            • 0
              Нет, основной смысл выражения — все-таки проверка на тип. Получение новой переменной — это побочный эффект.
            • –1
              Наверное удобнее и понятнее было бы как-то так:

              if(v as int => i)

              Или какое-то ключевое слово добавить вместо "=>"
              • +1
                мне кажется подобие кода типа if(v as int i) приведет в замешательство больше, т.к. as не может использоваться с value-type
            • +1
              Да ладно вам. Это же просто паттерн-матчинг.
              if (v is int i)
              

              Надо читать как «v — это какая-то интовая переменная i?»
  • 0
    Занятно. C# становится визуально более разболтанным, хотя всё ещё цельным внутри. Всё-таки его изначальная строгость подкупала. С другой стороны, это всё становится более удобным, похожим на прочие языки. Посмотрим, что из этого выйдет. Мне интересно, насколько быстро будет развиваться поддержка других систем и будет ли вообще. Сейчас мы имеем, скажем так, возможность хостить сайты где угодно, что снижает стоимость в какой-то мере. А остальное? Всё-таки кроссплатформенность — это, пожалуй, главный козырь Java, как прямого конкурента C#.
    • 0

      Хмм, если нужна "изначальная строгость", С++ вам в руки. Насчет кросс-платформенности, пока не появится портативный аналог WPF, кроссплатформенность будет только для веб и серверных приложений.

      • 0

        Сейчас уже существует Avalonia, правда конечно совсем еще альфа.

  • 0
    Код в картинках? Неужели нет подсветки си-шарпа?
    • +2
      Это вырезки из видеоролика презентации (что в том числе видно и по артефактам сжатия). Рекомендую, кстати, поглядеть.
  • +2
    В чем отличие 4. от интерполяции строк в C# 6?
    • +2
      Ни в чем. В видео интерполяцию использовали и упомянули, что эта фича уже есть в языке, а автор топика видимо решил, что это новая фича для C# 7.
      • 0
        Верно, интерполяция появилась недавно.
        Хочу заметить, что некоторые конструкции являются синтаксическим сахаром.

        Например, кортежи можно создавать прямо сейчас: msdn.microsoft.com/ru-ru/library/system.tuple%28v=vs.110%29.aspx
        • +1
          Не совсем — в F# кортежи являются плюшкой компилятора — в сборку добавляется служебный тип, который и являет собой необходимый кортеж. Подозреваю, что эти кортежи (C# 7) устроены аналогичным образом.
        • +2
          Там просто тип, а тут другое, видимо. Как минимум можно назначать элементам кортежа произвольные имена.
        • +1
          Tuple это класс, кортеж, если верить слухам, это будет неявная структура, то есть передача по значению без выделения памяти в куче.
  • 0
    Кортежи появились в .net 4.0, т.е. в 2010 году, через Tuple<T1-T8>.
    На stackoverflow вопросы об использовании кортежей, аж с 2010.
    Я так понимаю, что добавили возможность делать их анонимно(??? я никогда их не использовал, как я понимаю что тупо сахар добавили) или я что-то не понимаю?
    • 0
      Да, это такие себе анонимные кортежи с возможностью именовать свойства.
      • 0
        Это здорово (хотя я и не использую), но это большая разница, между «анонимные кортежи с возможностью именовать свойства» и «В С#7 появились кортежи».
        • 0
          Согласен. Все вопросы к автору :).
      • +2
        Плюс splatting:
        public double SomeMethod(int a, int b) => { };
        
        var t = new (int a, int b) { a = 1, b = 2 };
        
        SomeMethod(t);
        

        и unsplatting
        new List<(int a, int b)>().Add(1, 2);
        
    • +2
      Надо все-таки различать кортежи как не самый удобный обобщенный класс в стандартной библиотеке — и кортежи как элемент синтаксиса языка. Это разные вещи с просто совпавшим названием.

      Как элемент синтаксиса языка кортежи в C# появились впервые.
  • –1
    Блин, да когда же они readonly/val поддержку на уровне аргументов/переменных сделают?
  • 0
    В QML (Qt) есть тоже понятие свойства:
    Q_PROPERTY(int someProperty READ getSomeProperty WRITE setSomeProperty NOTIFY somePropertyChanged)
    

    Если написать:
    textBox.Text = obj.someProperty;
    

    То при изменении свойства внутри класса значение текстБокса будет обновлено автоматом. Об изменении свойства сообщит дополнительный сигнал somePropertyChanged.

    Я хотел бы видеть нечто подобное в C#. По мне так это и есть свойство. А то, что в C# имеется ввиду под свойством — обычный геттер и сеттер.

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.