Выбрать главу

OptArgMeth(1); // Ошибка из-за неоднозначности! Этот вызов приводит к неоднозначности потому, что компилятору неизвестно, ка кой именно вариант данного метода использовать: тот, где параметры beta и gamma имеют тип int, или же тот, где они имеют тип double. Но самое главное, что конкрет ный вызов метода OptArgMeth() может привести к неоднозначности, даже если она и не присуща его перегрузке. В связи с тем что перегрузка методов, допускающих применение необязательных аргументов, может привести к неоднозначности, очень важно принимать во внимание последствия такой перегрузки. В некоторых случаях, возможно, придется отказаться от применения необязательных аргументов, чтобы исключить неоднозначность и тем самым предотвратить использование метода непреднамеренным образом. ### Практический пример использования необязательных аргументов Для того чтобы показать на практике, насколько необязательные аргументы упро щают вызовы некоторых типов методов, рассмотрим следующий пример программы. В этой программе объявляется метод Display(), выводящий на экран символьную строку полностью или частично.

// Использовать необязательный аргумент, чтобы упростить вызов метода. using System;

class UseOptArgs { // Вывести на экран символьную строку полностью или частично. static void Display(string str, int start = 0, int stop = -1) { if (stop < 0) stop = str.Length; // Проверить условие выхода за заданные пределы. if(stop > str.Length | start > stop | start < 0) return; for(int i=start; i < stop; i++) Console.Write(str[i]); Console.WriteLine(); } static void Main() { Display("это простой тест"); Display("это простой тест", 12); Display("это простой тест", 4, 14); } } Выполнение этой программы дает следующий результат.

это простой тест тест простой те Внимательно проанализируем метод Display(). Выводимая на экран символьная строка передается в первом аргументе данного метода. Это обязательный аргумент, а два других аргумента — необязательные. Они задают начальный и конечный индексы для вывода части символьной строки. Если параметру stop не передается значение, то по умолчанию он принимает значение -1, указывающее на то, что конечной точкой вы вода служит конец символьной строки. Если же параметру start не передается значе ние, то по умолчанию он принимает значение 0. Следовательно, в отсутствие одного из необязательных аргументов символьная строка выводится на экран полностью. В про тивном случае она выводится на экран частично. Эго означает, что если вызвать метод Display() с одним аргументом (т.е. с выводимой строкой), то символьная строка будет выведена на экран полностью. Если же вызвать метод Display() с двумя аргументами, то на экран будут выведены символы, начиная с позиции, определяемой аргументом start, и до самого конца строки. А если вызвать метод Display() с тремя аргумента ми, то на экран будут выведены символы из строки, начиная с позиции, определяемой аргументом start, и заканчивая позицией, определяемой аргументом stop. Несмотря на всю простоту данного примера, он, тем не менее, демонстрирует зна чительное преимущество, которое дают необязательные аргументы. Это преимуще ство заключается в том, что при вызове метода можно указывать только те аргументы, которые требуются. А передавать явным образом устанавливаемые по умолчанию зна чения не нужно. Прежде чем переходить к следующей теме, остановимся на следующем важном мо менте. Необязательные аргументы оказываются весьма эффективным средством лишь в том случае, если они используются правильно. Они предназначены для того, чтобы метод выполнял свои функции эффективно, а пользоваться им можно было бы просто и удобно. В этом отношении устанавливаемые по умолчанию значения всех аргумен тов должны упрощать обычное применение метода. В противном случае необязатель ные аргументы способны нарушить структуру кода и ввести в заблуждение тех, кто им пользуется. И наконец, устанавливаемое по умолчанию значение необязательного параметра не должно наносить никакого вреда. Иными словами, неумышленное ис пользование необязательного аргумента не должно приводить к необратимым, отри цательным последствиям. Так, если забыть указать аргумент при вызове метода, то это не должно привести к удалению важного файла данных! ## Именованные аргументы Еще одним средством, связанным с передачей аргументов методу, является име нованный аргумент. Именованные аргументы были внедрены в версии C# 4.0. Как вам должно быть уже известно, при передаче аргументов методу порядок их следования, как правило, должен совпадать с тем порядком, в котором параметры определены в самом методе. Иными словами, значение аргумента присваивается параметру по его позиции в списке аргументов. Данное ограничение призваны преодолеть именованные аргументы. Именованный аргумент позволяет указать имя того параметра, которому присваивается его значение. И в этом случае порядок следования аргументов уже не имеет никакого значения. Таким образом, именованные аргументы в какой-то степени похожи на упоминавшиеся ранее инициализаторы объектов, хотя и отличаются от них своим синтаксисом. Для указания аргумента по имени служит следующая форма синтаксиса.

имя_параметра : значение Здесь имя_параметра обозначает имя того параметра, которому передается зна чение. Разумеется, имя_параметра должно обозначать имя действительного параме тра для вызываемого метода. Ниже приведен простой пример, демонстрирующий применение именованных аргументов. В этом примере создается метод IsFactor(), возвращающий логическое значение true, если первый его параметр нацело делится на второй параметр.

// Применить именованные аргументы. using System;

class NamedArgsDemo { // Выяснить, делится ли одно значение нацело на другое. static bool IsFactor(int val, int divisor) { if((val % divisor) == 0) return true; return false; } static void Main() { // Ниже демонстрируются разные способы вызова метода IsFactor(). // Вызов с использованием позиционных аргументов. if(IsFactor(10, 2)) Console.WriteLine("2 - множитель 10."); // Вызов с использованием именованных аргументов. if(IsFactor(val; 10, divisor: 2)) Console.WriteLine("2 - множитель 10."); // Для именованного аргумента порядок указания не имеет значения. if(IsFactor(divisor: 2, vaclass="underline" 10)) Console.WriteLine("2 - множитель 10."); // Применить как позиционный, так и именованный аргумент. if(IsFactor(10, divisor: 2)) Console.WriteLine("2 - множитель 10."); } } Выполнение этого кода дает следующий результат.

2 - множитель 10. 2 - множитель 10. 2 - множитель 10. 2 - множитель 10. Как видите, при каждом вызове метода IsFactor() получается один и тот же результат. Помимо демонстрации именованного аргумента в действии, приведенный выше пример кода иллюстрирует две важные особенности именованных аргументов. Во-первых, порядок следования аргументов не имеет никакого значения. Например, два следующих вызова метода IsFactor() совершенно равнозначны.

IsFactor(val :10, divisor: 2) IsFactor(divisor: 2, vaclass="underline" 10) Независимость от порядка следования является главным преимуществом имено ванных аргументов. Это означает, что запоминать (или даже знать) порядок следо вания параметров в вызываемом методе совсем не обязательно. Для работы с СОМ- интерфейсами это может быть очень удобно. И во-вторых, позиционные аргументы можно указывать вместе с именованными в одном и том же вызове, как показано в следующем примере.

IsFactor(10, divisor: 2) Следует, однако, иметь в виду, что при совместном использовании именованных и позиционных аргументов все позиционные аргументы должны быть указаны перед любыми именованными аргументами. Именованные аргументы можно также применять вместе с необязательными аргу ментами. Покажем это на примере вызова метода Display(), рассматривавшегося в предыдущем разделе.

// Указать все аргументы по имени. Display(stop: 10, str: "это простой тест", start: 0); // Сделать аргумент start устанавливаемым по умолчанию. Display(stop: 10, str: "это простой тест"); // Указать строку по позиции, аргумент stop — по имени by name, // тогда как аргумент start — устанавливаемым по умолчанию Display("это простой тест", stop: 10); Вообще говоря, комбинация именованных и необязательных аргументов позволяет упростить вызовы сложных методов со многими параметрами. Синтаксис именованных аргументов более многословен, чем у обычных позицион ных аргументов, и поэтому для вызова методов чаще всего применяются позиционные аргументы. Но в тех случаях, когда это уместно, именованные аргументы могут быть использованы довольно эффективно. **ПРИМЕЧАНИЕ** Помимо методов, именованные и необязательные аргументы могут применяться в конструкторах, индексаторах и делегатах. (Об индексаторах и делегатах речь пойдет далее в этой книге.) ## Метод Main() В представленных до сих пор примерах программ использовалась одна форма ме тода Main(). Но у него имеется также целый ряд перегружаемых форм. Одни из них могут служить для возврата значений, другие — для получения аргументов. В этом разделе рассматриваются и те и другие формы. #### Возврат значений из метода Main() По завершении программы имеется возможность возвратить конкретное значение из метода Main() вызывающему процессу (зачастую операционной системе). Для этой цели служит следующая форма метода Main().

static int Main() Обратите внимание на то, что в этой форме метода Main() объявляется возвращае мый тип int вместо типа void. Как правило, значение, возвращаемое методом Main(), указывает на нормальное завершение программы или на аварийное ее завершение из-за сложившихся ненор мальных условий выполнения. Условно нулевое возвращаемое значение обычно ука зывает на нормальное завершение программы, а все остальные значения обозначают тип возникшей ошибки. ### Передача аргументов методу Main() Многие программы принимают так называемые аргументы командной строки, т.е. информацию, которая указывается в командной строке непосредственно после имени программы при ее запуске на выполнение. В программах на C# такие аргумен ты передаются затем методу Main(). Для получения аргументов служит одна из при веденных ниже форм метода Main().