Новые возможности C# 4.0. Часть 2: параметры по умолчанию

Автор оригинала: Justin Etheredge
  • Перевод
Сегодня мы поговорим о другой новинке C# 4.0, которую я ждал много лет. В прошлом, ее отсутствие объяснялось архитектурным решением. Но, видимо, прагматизм победил и теперь у нас есть параметры по умолчанию. Чтобы сделать их еще более полезными они добавили к ним именованые параметры. Мы обсудим их через пару минут, а сейчас займемся параметрами по умолчанию.

Предположим, что у нас есть такой класс:
  1. public class TestClass
  2. {
  3.   public void PerformOperation(string val1, int val2, double val3)
  4.   {
  5.     Console.WriteLine("{0},{1},{2}", val1, val2, val3);
  6.   }
  7. }
* This source code was highlighted with Source Code Highlighter.
Теперь мы можем инстанциировать его и вызвать метод:
  1. var testClass = new TestClass();
  2. testClass.PerformOperation("val", 10, 12.2);
* This source code was highlighted with Source Code Highlighter.
Но, что, если мы знаем «хорошие» значения параметров, которые используются чаще всего? До сего дня решением являлась перегрузка методов:
  1. public class TestClass
  2. {
  3.   public void PerformOperation()
  4.   {
  5.     PerformOperation("val", 10, 12.2);
  6.   }
  7.   
  8.   public void PerformOperation(string val1)
  9.   {
  10.     PerformOperation(val1, 10, 12.2);
  11.   }
  12.  
  13.   public void PerformOperation(string val1, int val2)
  14.   {
  15.     PerformOperation(val1, val2, 12.2);
  16.   }
  17.  
  18.   public void PerformOperation(string val1, int val2, double val3)
  19.   {
  20.     Console.WriteLine("{0},{1},{2}", val1, val2, val3);
  21.   }
  22. }
* This source code was highlighted with Source Code Highlighter.
Довольно длинно. Но C# 4.0 дает нам лучшее решение:
  1. public class TestClass
  2. {
  3.   public void PerformOperation(string val1 = "val", int val2 = 10, double val3 = 12.2)
  4.   {
  5.     Console.WriteLine("{0},{1},{2}", val1, val2, val3);
  6.   }
  7. }
* This source code was highlighted with Source Code Highlighter.
Насколько это чище, а? Как же нам теперь вызывать этот метод? Да точно так же, если бы это была перегрузка:
  1. var testClass = new TestClass();
  2. testClass.PerformOperation("val", 10);
* This source code was highlighted with Source Code Highlighter.
Очень хорошо. Третий параметр в этом вызове приравнен к 12.2 по умолчанию. Теперь VB.NET разработчики перестанут смеятся над нами. Более того, параметры по умолчанию распространяются и на конструкторы:
  1. public class TestClass
  2. {
  3.   public TestClass(string someValue = "testValue")
  4.   {
  5.   }
  6.  
  7.   public void PerformOperation(string val1 = "val", int val2 = 10, double val3 = 12.2)
  8.   {
  9.     Console.WriteLine("{0},{1},{2}", val1, val2, val3);
  10.   }
  11. }
* This source code was highlighted with Source Code Highlighter.
Больше никаких многократных перегрузок конструкторов!

А что случится, если мы опустим значение val2 в вызове метода, показаном выше? Тоесть мы хотим указать val1 и val3, но оставить значение по умолчанию для val2. Мы не можем сделать это так:
  1. var testClass = new TestClass();
  2. testClass.PerformOperation("val", 10.2);
* This source code was highlighted with Source Code Highlighter.
Этот код не скомпилируется, так как 10.2 не может быть приведено к int — здесь C# пытается оставить по умолчанию третий параметр, а не второй, как нам нужно. Итак, какой выход у нас есть? Мы можем использовать именованые параметры. Они состоят из указания имени параметра, двоеточия и значения, которое мы передаем. Тоесть вызов будет выглядеть так:
  1. var testClass = new TestClass();
  2. testClass.PerformOperation("val", val3: 10.2);
* This source code was highlighted with Source Code Highlighter.
Довольно аккуратно, но меня смущает тот факт, что теперь смена имени параметра будет нести такие кардинальные последствия. Я думаю только время покажет насколько это удобно в разработке больших приложений. Хотя, люди, работающие с другими языками живут с этим уже много лет.

Вот вам еще одна интересная новая возможность C# 4.0 и еще один повод приглядываться к новой VS2010.

Перевод статьи: C# 4.0 New Features Part 2 — default and named parameters

Кросспост из моего блога

Поделиться публикацией

Комментарии 60

    +2
    наконец таки они появились. отсутствие параметров по умолчанию и необходимость перегрузок чтобы добиться желаемого результата очень удручала. с нетерпением жду описания новых фкусностей четвертого дот нета!
      +3
      лучше бы уж параметры пропускались запятой как в php или в том же бейсике
        0
        тоже хорошая мысль, думаю такой вариант был бы даже намного лучше, ведь не было бы привязки к именам параметров.
          0
          Просто парни из Реймонда взяли то, что было реализовано в коке немного раньше. Вы не поверите, но так действительно удобнне )
            0
            Зависит от того сколько в среднем параметров нужно передать методу, если опускается пара параметров из, например, двадцати, то через запятые удобнее, но если из двадцати только пару нужно передать, то рулят именованные параметры.
              +1
              если методу передается 20 параметров, то фтопку такой метод — нужно разделить его на подзадачи
                0
                А как вы будете работать с Экселем? Перепишите Эксель? :)
                  0
                  у екселя есть методы с 20ю параметрами?
                    0
                    Там и с тридцатью двумя есть.
                    А вообще, при разработке распределённых приложений функции с большим количеством параметров — нормальное явление.
                0
                Не могу не соглоситься, но могу дополнить.
                Вероятность ошибки при передаче параметров именованными значеними намного ниже. В теперешних реалях программирования этот факт нельзя не учитывать. Но комментарий был не об этом )
              0
              да, запятая самое то и наглядно и не будет последствий от переименования,
              но вот у майкрософт бывают загоны, далее выпустят C# 4.1, в нем будет запятой пропускаться.
                0
                Последствия от переименований решаются средствами автоматического рефакторинга. А запятые можно будет умаяться считать.
              0
              Прошу прощение за вопрос, однако почему вы перевод не делаете как топик-перевод? Мне кажется, так удобнее даже для Вас было бы.
                +2
                Вот незадача: меня смутила ссылка на оригинальный топик, данная дважды. ;-)
                  +1
                  Как не делаю? Вроде именно этот тип топика и выбираю. Даже иконка стоит:
                  0
                  Кроме телескопа из примера есть ещё замечательный Builder Pattern.
                  • НЛО прилетело и опубликовало эту надпись здесь
                      0
                      Отличное решение. Больше никаких перегрузок!
                        +2
                        ну не скажите, иногда перезагрузка удобнее.
                        правильнее будет «Больше никаких ненужных перегрузок!» ;)
                          –2
                          Весьма тонкая грань в вашем ответе.
                          Никак не могу придумать пример, в котором обычная перегрузка была бы удобнее.
                            +5
                            new SqlGreateWrapper(string connectionString);
                            new SqlGreateWrapper(SqlConnection connection);
                              0
                              точно. у меня правда первая мысль была про потоки и пути к файлам :")

                              З.Ы.: если про Sql то нагляднее будет connectionString и SqlConnectionStringBuilder ;)
                        0
                        А кто-нибудь знает, как это реализовано?
                        На уровне атрибутов или какие-то нововведения в CLR?
                          0
                          что-то мне подсказывает что перезагрузками, просто теперь отпадает необходимость писать их самостоятельно… хотя именованные параметры смущают, их простой перегрузкой не реализовать…
                            0
                            Ну да, наверно так и есть. Именованные параметры тоже просто сделать таким способом.
                            0
                            Скорее всего компилятор сам подставляет нужные значения. Тоесть Вы пишите testClass.PerformOperation(«val», val3: 10.2); а компилятор преобразует это в testClass.PerformOperation(«val», 10, 12.3);
                            никаких атрибутов, да и CLR, насколько я знаю, из-за совместимости изменения вноситься не могут. Все новшества — это очень-очень вкусный «синтаксический сахар»
                              +1
                              Если так, то эта фича не будет работать с откомпилированными библиотеками, если исходного кода нет под рукой. Мета-информация о значениях по-умолчанию должна быть известна.
                                0
                                +1
                                  +1
                                  что ставит под сомнение скорость вызова таких методов
                                    0
                                    Атрибуты, на сколько я понял, нужны компилятору. Он определяет дефолтные значения во время компиляции и подставляет их в параметры в виде констант. Так что скорость работы не изменится.
                                      0
                                      похоже что нет
                                      по ссылке которую я привел атрибуты у методов присутствуют в скомпилированном коде
                                      цитата:

                                      Let's look through .NET Reflector to see the generated code for the constructor.
                                      public TextBoxInfo(
                                      [Optional, DefaultParameterValue("")] string text,
                                      [Optional, DefaultParameterValue(10f)] float size,
                                      [Optional, DefaultParameterValue(50f)] float width,
                                      [Optional] Color color)
                                      {
                                      this.text = text;
                                      this.size = size;
                                      this.width = width;
                                      this.color = color;
                                      }
                                        0
                                        Ну да, а при вызове этого метода без параметров сгенерится такой код:

                                        new TextBoxInfo("", 10f, 50f, null);
                                          0
                                          да, вы правы, похоже ничего страшного нет
                                +1
                                классно, спасибо. а на счет гемора с указанием именнованного параметра и трудностями чтобы сменить его название, а разве Rename тут не работает так же как с переменными? я надеюсь эта возможность реализована в этом случае
                                  0
                                  Это зависимость от инструмента разработки получается. Откроете вы как-нибудь файл в блокноте, смените название параметра — тут все и не скомпилируется.
                                    0
                                    ну это крайности :) это одно и тоже что если вы название какого-то метода захотите поменять, без VS тоже не удобно :)) Есть конечно банальный Replace в блокноте, но это не выход же :)
                                  +1
                                  Что-то посказывает, что из c# делают некий анти-паттерн God Language, который есть смесь всего самого лучшего из Basic`а, Java`ы, php, с++ и прочего.

                                  Удобно конечно, но тогда давайте и множественное наследование введем.

                                  Где-то здесь подвох зарылся, а где — покажет время.
                                    +1
                                    Согласен. И вообще, мне не понятно, неужели C# 3.0 настолько изжил себя, что возникла острая необходимость в следующей версии? Многие ещё до сих пор LINQ не освоили…
                                      0
                                      Да и не только Linq. Workflow тоже полезная штука.
                                        0
                                        … которая к самому языку никакого отношения не имеет.
                                        –2
                                        полностью с вами согласен :)
                                        0
                                        множественное наследование по-моему в шарпе не будет никогда, они заменили эту фичу наследованием от нескольких интерфейсов. чо-то подобное — не помню точно
                                          0
                                          Не совсем. Они сделали отдельную конструкцию «интерфейс» (в плюсах ее нет, вместо нее используются абстрактные классы), и разрешили множественное наследование только от нее, что мне лично очень нравится.
                                            0
                                            спасибо :)
                                        +1
                                        Даже не знаю, что и сказать. Дефолтные значения довольно удобны, а вот именованные параметры буду стараться использовать как можно меньше, только там, где это действительно необходимо.
                                          0
                                          Ндяс, сначала С# представлял из себя эдакий маленький удобный язык, который даже школьник поймёт — лёгкая замена Бейсику, конкурент Java, простая альтернатива сложному и коварному С++.

                                          Но теперь мне кажется что совсем скоро С# сможет тягаться в сложности с С++ — и очарование пропадёт :)
                                            0
                                            Разве что из-за .NET наворотов.
                                              –1
                                              Еще пару лет и шарп будет неотличим от плюсов. Все к тому идет. Шаблоны ввели, вот, наконец-то, параметры сделали. Еще пару штрихов и всё — привет, плюсы :)
                                                0
                                                Это все — коварный план по тайному пересаживанию народа на плюсы :-)
                                                  +1
                                                  Шаблоны в плюсах — это инструмент метапрограммирования, а в шарпе полиморфизма. Их нельзя сравнивать, без многих но.
                                                0
                                                Иногда, это будет удобно, да. Но вот конструкторы такие я им не прощу никогда. Дебильно спроектированные indian-style классы, привет вам.
                                                  +1
                                                  Черезвычайно полезно, когда появляются вот такие вот статьи. Так, постепенно, маленькими дозами можно легко освоить все нововведения языка. Буду рад, если они будут появляться и дальше, чтобы с выходом C# 4.0 свободно пользоваться новыми возможностями.
                                                    +2
                                                    Да уж, не знаю, радоваться этому, или нет… Использование перегрузки однозначно говорило о том, что дефолтные параметры — плохо. Теперь это вроде как чисто и красиво.
                                                      +1
                                                      Смешно если честно.
                                                      Delphi имел параметры по умолчанию не помню с какой точно, но точно с младших версий. У C# разработчик языка один и тот же, а только собираются вводить такую фичу.
                                                        0
                                                        Параметры по умолчанию это очень удобно!

                                                        Интересно, а когда сделают константные параметры…
                                                          0
                                                          Вы не поверите, но в 1С и в Аксапте подобное объявление давно не новость
                                                            0
                                                            А что будет, если:

                                                            class Test
                                                            {
                                                            public Test () { Console.WriteLine («1»); }
                                                            public Test (string message = «2») { Console.WriteLine (message); }
                                                            }


                                                            Test test = new Test ();

                                                            ?
                                                              0
                                                              Так как не имею под рукой 2010 студии предположу, что не скомпилируется
                                                              0
                                                              Всегда от этих перегрузок тошнило, из-за них сижу на VB и над C#-щиками действительно злостно посмеиваюсь :) Теперь наверно скоро на C# можно будет переходить, правда не думаю, что в этот раз параметры по умолчанию сделают достаточно хорошо. Чего-нибудь обязательно не доделают, взять хотя бы эти запятые.

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