1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 37
Текст из файла (страница 37)
К счастью, в C# предусмотрена альтернатива получше, а именноиспользование модификатора out.Модификатор out подобен модификатору ref за одним исключением: его можноиспользовать только для передачи значения из метода. Совсем не обязательно (и даже ненужно) присваивать переменной, используемой в качестве out-параметра, начальноезначение до вызова метода.
Более того, предполагается, что out-параметр всегда“поступает” в метод без начального значения, но метод (до своего завершения) обязательнодолжен присвоить этому параметру значение. Таким образом, после обращения к методуout-параметр будет содержать определенное значение.Перед вами пример использования out-параметра.
В классе Decompose методparts() разбивает вещественное число на целую и дробную части. Обратите внимание нато, как возвращается автору вызова этого метода каждый компонент.// Использование модификатора out.using System;class Decompose {/* Метод разбивает число с плавающей точкой нацелую и дробную части. */public int parts(double n, out double frac) {int whole;whole = (int) n;}}frac = n - whole; // Передаем дробную часть// посредством параметра frac.return whole; // Возвращаем целую часть числа.class UseOut {public static void Main() {Decompose ob = new Decompose();Глава 8.
Подробнее о методах и классах193int i; double f;i = ob.parts(10.125, out f);}}Console.WriteLine("Целая часть числа равна " + i);Console.WriteLine("Дробная часть числа равна " + f);При выполнении этой программы получаем такие результаты:Целая часть числа равна 10Дробная часть числа равна 0,125Метод parts() возвращает два значения. Целая часть числа n возвращается спомощью инструкции return. Дробная часть числа n передается автору вызовапосредством out-параметра frac. Как показывает этот пример, используя out-параметр,можно добиться того, чтобы метод возвращал не одно, а два значения.Более того, синтаксис языка C# не ограничивает вас использованием только одногоout-параметра. Метод может возвращать посредством out-параметров столько значений,сколько вам нужно.
Ниже приводится пример использования двух out-параметров. МетодisComDenom() выполняет две функции. Во-первых, он определяет, существует ли у двухзаданных целых чисел общий множитель. При этом метод возвращает значение true, еслитакой множитель существует, и значение false в противном случае. Во-вторых, если этичисла таки имеют общий множитель, метод isComDenom() с помощью out-параметроввозвращает наименьший и наибольший общие множители.// Демонстрация использования двух out-параметров.using System;class Num {/* Метод определяет, имеют ли x и v общий множитель.Если да, метод возвращает наименьший и наибольшийобщие множители в out-параметрах. */public bool isComDenom(int x, int y,out int least,out int greatest) {int i;int max = x < y ? x : y;bool first = true;least = 1;greatest = 1;// Находим наименьший и наибольший общие множители.for(i=2; i <= max/2 + 1; i++) {if( ((y%i)==0) & ((x%i)==0) ) {if(first) {least = i;first = false;}greatest = i;}}if(least != 1) return true;194Часть I.
Язык C#}}else return false;class DemoOut {public static void Main() {Num ob = new Num();int lcd, gcd;if(ob.isComDenom(231, 105, out lcd, out gcd)) {Console.WriteLine("Lcd для чисел 231 и 105 равен " +lcd);Console.WriteLine("Gcd для чисел 231 и 105 равен " +gcd);}elseConsole.WriteLine("Для чисел 35 и 49 общего множителя нет.");}}if(ob.isComDenom(35, 51, out lcd, out gcd)) {Console.WriteLine("Lcd для чисел 35 и 51 равен " +lcd);Console.WriteLine("Gcd для чисел 35 и 51 равен " +gcd);}elseConsole.WriteLine("Для чисел 35 и 51 общего множителя нет.");Обратите внимание на то, что в функции Main() переменным lcd и gcd неприсваиваются значения до вызова функции isComDenom().
Это было бы ошибкой, еслибы эти переменные были не out-, a ref-параметрами. Этот метод в зависимости отсуществования общих множителей у заданных двух чисел возвращает либо true, либоfalse. Причем, если общие множители существуют, то наименьший и наибольший из нихвозвращаются в out-параметрах led и gcd, соответственно.
(Lcd — это аббревиатура отleast common denominator, т.е. наименьший общий множитель, a gcd — это аббревиатура отgreatest common denominator, т.е. наибольший общий множитель.) Вот каковы результатывыполнения этой программы:Lcd для чисел 231 и 105 равен 3Gcd для чисел 231 и 105 равен 21Для чисел 35 и 51 общего множителя нет.Использование модификаторов ref и out для ссылочных параметровИспользование модификаторов ref и out не ограничивается параметрами типазначений. Их также можно применить к ссылочным параметрам, т.е. параметрам,обеспечивающим передачу объектов.
Если параметр ссылочного типа модифицируетсяодним из модификаторов ref и out, то по сути реализуется передача ссылки по ссылке.Это позволяет методу изменять объект, на который указывает ссылка-параметр.Рассмотрим программу, в которой используются ссылочные ref-параметры для обменаобъектами, на которые указывают две ссылки.Глава 8.
Подробнее о методах и классах195// Обмен двух ссылок.using System;class RefSwap {int a, b;public RefSwap(int i, int j) {a = i;b = j;}public void show() {Console.WriteLine("a: {0}, b: {1}", a, b);}}// Этот метод теперь изменяет свои аргументы.public void swap(ref RefSwap ob1, ref RefSwap ob2) {RefSwap t;t = ob1;ob1 = ob2; ob2 = t;}class RefSwapDemo {public static void Main() {RefSwap x = new RefSwap(1, 2);RefSwap y = new RefSwap(3, 4);Console.Write("x перед вызовом: ");x.show();Console.Write("y перед вызовом: ");y.show();Console.WriteLine();// Обмениваем объекты, на которые ссылаются x и y.x.swap(ref x, ref y);Console.Write("x после вызова: ");x.show();}}Console.Write("y после вызова: ");y.show();При выполнении этой программы получаем такие результаты:x перед вызовом: a: 1, b: 2y перед вызовом: a: 3, b: 4x после вызова: a: 3, b: 4y после вызова: a: 1, b: 2196Часть I.
Язык C#В этом примере метод swap() меняет местами объекты, на которые ссылаются дваего аргумента. До вызова метода swap() переменная x ссылается на объект, которыйсодержит значения 1 и 2, а переменная y ссылается на объект, который содержит значения 3и 4. После обращения к методу swap() переменная x ссылается на объект, которыйсодержит значения 3 и 4, а переменная y ссылается на объект, который содержит значения 1и 2. Если бы здесь не были использованы ref-параметры, то обмен внутри метода swap()никак не повлиял бы на “среду” за его пределами. Это можно доказать, убравмодификаторы из метода swap().Использование переменного количествааргументовПри создании метода обычно заранее известно количество аргументов, которыебудут ему передаваться. Но иногда необходимо, чтобы метод принимал произвольное числоаргументов. Рассмотрим, например, метод, который находит минимальное значение внаборе чисел.
Такому методу может быть передано два, три или четыре значения. В любомслучае метод должен возвращать наименьшее значение. Такой метод невозможно создатьпри использовании обычных параметров. Здесь необходимо применить специальный типпараметра, который заменяет собой произвольное количество параметров. Это реализуетсяс помощью модификатора params.Модификатор params используется для объявления параметра-массива, которыйсможет получить некоторое количество аргументов (в том числе и нулевое). Количествоэлементов в массиве будет равно числу аргументов, переданных методу.Рассмотрим пример, в котором модификатор params используется для созданияметода minVal(), возвращающего минимальное значение из набора.// Демонстрация использования модификатора params.using System;class Min {public int minVal(params int[] nums) {int m;if(nums.Length == 0) {Console.WriteLine("Ошибка: нет аргументов.");return 0;}m = nums[0];}}for(int i=1; i < nums.Length; i++)if(nums[i] < m) m = nums[i];return m;class ParamsDemo {public static void Main() {Min ob = new Min();int min;int a = 10, b = 20;Глава 8.
Подробнее о методах и классах197// Вызываем метод с двумя значениями.min = ob.minVal(a, b);Console.WriteLine("Минимум равен " + min);// call with 3 valuesmin = ob.minVal(a, b, -1);Console.WriteLine("Минимум равен " + min);// Вызываем метод с пятью значениями.min = ob.minVal(18, 23, 3, 14, 25);Console.WriteLine("Минимум равен " + min);}}// Этот метод можно также вызвать с int-массивом.int[] args = { 45, 67, 34, 9, 112, 8 };min = ob.minVal(args);Console.WriteLine("Минимум равен " + min);Вот результаты выполнения этой программы:Минимум равен 10Минимум равен -1Минимум равен 3Минимум равен 8При каждом вызове метода minVal() аргументы передаются ему через массивnums. Длина этого массива равна количеству элементов.
Поэтому метод minVal() можноиспользовать для определения минимального из любого числа элементов.Несмотря на то что params-параметру можно передать любое количествоаргументов, все они должны иметь тип, совместимый с типом массива, заданным этимпараметром. Например, такой вызов метода minVal()min = ob.minVal(1, 2.2);неверен, поскольку автоматического преобразования значения типа double(2.2) взначение типа int (тип int имеет массив nums в методе minVal()) не существует.При использовании модификатора params необходимо внимательно отнестись кграничным ситуациям задания аргументов, поскольку params-параметр может принятьлюбое количество аргументов, даже нулевое! Например, синтаксически вполне допустимовызвать метод minVal() следующим образом:min = ob.minVal(); // аргументы отсутствуютmin = ob.minVal(3); // один аргументВот поэтому в методе minVal() до попытки доступа к элементу массива numsпредусмотрена проверка существования хотя бы одного элемента в массиве.
Если бы такаяпроверка отсутствовала, то при вызове метода minVal() без аргументов имела бы местоисключительная ситуация. (Ниже в этой книге при рассмотрении исключительныхситуаций будет показан более удачный способ обработки таких типов ошибок.) Более того,код метода minVal() был написан так специально, чтобы разрешить его вызов с однимаргументом. В этом случае метод возвращает этот (единственный) аргумент.Наряду с обычными параметрами методы могут иметь и параметр переменной длины.Например, в следующей программе метод showArgs() принимает один параметр типаstring и params-массив целочисленного типа.// Использование обычного параметра вместе// с params-параметром.198Часть I.
Язык C#using System;class MyClass {public void showArgs(string msg, params int[] nums) {Console.Write(msg + ": ");}}foreach(int i in nums)Console.Write(i + " ");Console.WriteLine();class ParamsDemo2 {public static void Main() {MyClass ob = new MyClass();}}ob.showArgs("Вот несколько целых чисел",1, 2, 3, 4, 5);ob.showArgs("А вот еще два числа",17, 20);Программа генерирует следующие результаты:Вот несколько целых чисел: 1 2 3 4 5А вот еще два числа: 17 20Когда метод принимает обычные параметры и params-параметр, params-параметрдолжен стоять в списке параметров последним и быть единственным в своем роде.Возвращение методами объектовМетод может возвращать данные любого типа, в том числе классового.