В языке C# существуют два типа переменных - типы, характеризуемые значением и ссылочные типы. Переменные типа значения содержат именованные данные, к которым относятся все числовые типы, структуры и перечисления. Они создаются при компиляции программы и размещаются в стековой области памяти при их загрузке. Ссылочные типы содержат адреса участков памяти, создаваемых динамически при выполнении программы, и представляют неименованные данные.
| Объявление типа | Создание объекта | Альтернативный синтаксис создания объекта |
|---|---|---|
| Встроенный тип, характеризуемый значением | int a; |
int a = new int(); |
Пользовательский тип, характеризуемый значением struct MyStruct
{
public x, y;
}
|
MyStruct point; |
MyStruct point = new MyStruct(); |
Пользовательский тип, характеризуемый ссылкойstruct MyClass
{
public x, y;
}
|
// Объявили ссылку MyClass point; // Создали и привязали объект point = new MyClass(); |
MyClass point = new MyClass(); |
На случай применения одинакового синтаксиса конструктор по умолчанию без параметров за типами значений зарезервирован и его переопределять нельзя. Можно только дополнить тип параметризованными конструкторами.
При выполнении операции присваивания в переменные типа значений копируются сами данные, в переменные типа ссылок копируется адрес расположения одних и тех же данных.
В C# формальные параметры метода при его объявлении называют просто параметрами, а фактические параметры, передаваемые методу при его вызове - аргументами. Статические методы и C# предлагается множество модификаторов параметров, которые обеспечивают контроль со стороны компилятора за действиями программиста при вызове этих методов и передаче им
| Модификатор | Описание |
|---|---|
| (нет) | Если параметр метода не помечен модификатором, то предполагается передача параметра по значению, т.е. в вызываемый метод передается копия оригинальных данных |
out |
Выходной параметр устанавливается вызываемым методом и передается по ссылке. Если вызываемый метод не присвоит выходному параметру значение, то генерируется ошибка компиляции |
params |
Позволяет переслать произвольное число аргументов одинакового типа в виде единого параметра. Для любого метода допускается только один модификатор params и только для последнего по порядку следования параметра |
ref |
Передается ссылка на данные клиента, которые метод может менять внутри себя. Фактически метод работает с данными, размещенными вне его |
Внутренние ( private ) методы класса обычно параметров не имеют, поскольку все объявленные в классе поля видимы внутри методов класса. Параметры нужны для общедоступных ( public ) методов, с которыми общаются клиенты класса и передают через них новые значения данных. Такие методы называются интерфейсными, включая и конструкторы.
При передаче именованного параметра он передается по значению, т.е. внутри метода создается копия подключенных данных и метод работает с этой копией. Оригинальные данные клиента метода не меняются и вызывающая сторона не увидит выполненных изменений. Это самый безопасный способ передачи, когда по исходным данным нужно получить какой-то результат, оставив сами данные без изменений.
Приведем простой пример.
using System;
static class Calculator
{
public static int Add(int x, int y, int a, int b)
{
int answer = x + y;
x = 10; y = 20; a = 30; b = 40;
return answer;
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Настройка консоли
Console.Title = "Передача параметров по значению";
Console.ForegroundColor = ConsoleColor.White;
Console.CursorVisible = false;
int x = 1, y = 2, a = 3, b = 4;
Console.WriteLine("До вызова: \tx={0}; y={1}; a={2}; b={3}",
x, y, a, b);
Calculator.Add(x, y, a, b);
Console.WriteLine("После вызова: \tx={0};
y={1}; a={2}; b={3}",
x, y, a, b);
Console.ReadLine();
}
}
Результат будет таким

Мы видим, что переприсваивание значений параметрам внутри метода не влияет на изменения данных, хранящихся в вызывающей стороне, поскольку метод работает с копиями.
Следует отметить, что когда методу передается ссылка на объект, то метод всегда работает с внешними данными, то есть с самим объектом.
Часть параметров, которым планируется внутри метода выполнить изменения значений, следует обозначать как выходные с помощью ключевого слова out. Это требуется делать и в объявлении метода, и в его вызове.
Пометим в предыдущем примере два параметра как выходные. Код будет таким
using System;
static class Calculator
{
public static int Add(int x, int y, out int a, out int b)
{
int answer = x + y;
x = 10; y = 20; a = 30; b = 40;
return answer;
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Настройка консоли
Console.Title = "Применение выходных параметров";
Console.ForegroundColor = ConsoleColor.White;
Console.CursorVisible = false;
int x = 1, y = 2, a = 3, b = 4;
Console.WriteLine("До вызова: \tx={0};
y={1}; a={2}; b={3}",
x, y, a, b);
Calculator.Add(x, y, out a, out b);
Console.WriteLine("После вызова: \tx={0};
y={1}; a={2}; b={3}",
x, y, a, b);
Console.ReadLine();
}
}
Выполним пример

Мы видим, что отмеченные как выходные параметры меняют в вызывающем коде свои значения. Им в клиенте не обязательно присваивать значения, все равно метод их изменит.
Ссылки представляют собой адреса участков памяти, где хранятся данные. Если методу передать ссылку на эту память, то он будет работать с самими данными, а не их копиями, как это происходит с передачей параметра по значению. Если ссылке не присвоить конкретный адрес перед ее передачей методу, то сгенерируется ошибка компиляции, поскольку нельзя использовать в методе неинициализированные данные, в том числе и ссылки.
Добавим в предыдущем примере в объявление и вызов первых двух параметров метода Add() модификатор ref ( reference - ссылка), заставляющий компилятор включить механизм передачи этих параметров по ссылке. Код станет таким
using System;
static class Calculator
{
public static int Add(ref int x, ref int y, out int a, out int b)
{
int answer = x + y;
x = 10; y = 20; a = 30; b = 40;
return answer;
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Настройка консоли
Console.Title = "Передача параметров по ссылке";
Console.ForegroundColor = ConsoleColor.White;
Console.CursorVisible = false;
int x = 1, y = 2, a = 3, b = 4;
Console.WriteLine("До вызова: \tx={0};
y={1}; a={2}; b={3}",
x, y, a, b);
Calculator.Add(ref x, ref y, out a, out b);
Console.WriteLine("После вызова: \tx={0};
y={1}; a={2}; b={3}",
x, y, a, b);
Console.ReadLine();
}
}
Получим результат

Метод внутри себя меняет значения данных клиента, переданных по ссылке.
Объекты ссылочного типа адресуются в программе ссылками. Их также можно передать методам по значению. Только при этом в методе создается не копия объекта, а копия ссылки ( alias - псевдоним), которая будет адресоваться к тому же объекту. Это значит, что метод будет работать с самим переданным объектом, а не с его копией. Но попытка изменить значение самого псевдонима никак не отразится на переданной из клиента ссылке - она в клиенте по-прежнему будет адресоваться к самому объекту.
using System;
class MyClass
{
// Открытые поля
public int a, b;
// Конструктор
public MyClass(int a, int b)
{
this.a = a;
this.b = b;
}
// Печать
public void Show()
{
Console.WriteLine("a={0}, b={1}", a, b);
}
}
class Start
{
static void ChangeObject(MyClass ob)
{
ob.a = 10;
ob.b = 20;
ob = null; // Изменяем копию ссылки
}
static void Main()// Вызывающая сторона
{
// Настройка консоли
Console.Title = "Передача методу объекта ссылочного типа";
Console.ForegroundColor = ConsoleColor.White;
Console.CursorVisible = false;
// Создаем объект
MyClass ob1 = new MyClass(1, 2);
Console.Write("До вызова: \t"); ob1.Show();
// Передаем методу объект в виде ссылки
ChangeObject(ob1);
Console.Write("После вызова: \t"); ob1.Show();
Console.ReadLine();
}
}
Результат будет таким

Если в метод передать ссылку на объект с модификатором ref, тогда в методе окажется адресная переменная самой ссылки (ссылка на ссылку) и смена значения этой адресной переменной изменит значение ссылки, что приведет к потере объекта или к адресации на новый объект.
using System;
static class Swap
{
public static void SwapRef(ref string str1, ref string str2)
{
string tmp = str1;
str1 = str2;
str2 = tmp;
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Настройки консоли
Console.Title = "Обмен строк через адреса";
Console.ForegroundColor = ConsoleColor.White; // Белый текст
Console.WindowWidth = 45;// Знакомест клиентской области
Console.WindowHeight = 3;// Строк клиентской области
Console.CursorVisible = false;
// Вызывающий код
string string1 = "Первая строка";
string string2 = "Вторая строка";
Console.WriteLine("До вызова: \t{0},
{1}", string1, string2);
Swap.SwapRef(ref string1, ref string2);
Console.WriteLine("После вызова: \t{0},
{1}", string1, string2);
Console.ReadLine();
}
}
Поскольку строки представляют собой объекты ссылочного типа, то метод обменивает значения ссылок, которые будут адресоваться к новым строкам.
Результат выполнения будет таким

Вот еще один пример.
using System;
using System.IO;
using System.Text;
class MyClass
{
// Печать в свойство, базового поля нет
public String Result
{
get
{
return String.Format("a={0}, b={1}", a, b);
}
}
// Закрытые поля
int a, b;
// Конструктор
public MyClass(int a, int b)
{
this.a = a;
this.b = b;
}
public static void SwapRef(ref MyClass ob1,
ref MyClass ob2, ref MyClass obNew)
{
MyClass tmp;// Объявляем вспомогательную ссылку
// Обмениваем значения ссылок
tmp = ob1;
ob1 = ob2;
ob2 = tmp;
// Создаем новый объект и прикрепляем к ссылке клиента
obNew = new MyClass(5, 6);
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Настройки консоли
Console.Title = "Обмен объектов через адреса";
Console.ForegroundColor = ConsoleColor.White; // Белый текст
Console.CursorVisible = false;
// Создаем и открываем поток вывода в файл
StreamWriter writeFile =
new StreamWriter(@"C:\1\xx.txt", false,
ASCIIEncoding.GetEncoding(1251));
// Вызывающий код
// Создаем объекты
MyClass ob1 = new MyClass(1, 2);
MyClass ob2 = new MyClass(3, 4);
// Создаем ссылку без объекта
MyClass ob3 = null;
writeFile.WriteLine("До вызова: ");
writeFile.WriteLine(ob1.Result);
writeFile.WriteLine(ob2.Result);
writeFile.WriteLine();
// Передаем методу объект в виде ссылки
MyClass.SwapRef(ref ob1, ref ob2, ref ob3);
writeFile.WriteLine("После вызова: ");
writeFile.WriteLine(ob1.Result);
writeFile.WriteLine(ob2.Result);
writeFile.WriteLine(ob3.Result);
writeFile.Close();
}
}
Результат выполнения будет размещен в автоматически созданном текстовом файле с нашим именем xx.txt и будет таким
До вызова: a=1, b=2 a=3, b=4 После вызова: a=3, b=4 a=1, b=2 a=5, b=6
В последнем приведенном коде мы немножко отвлеклись от темы и сделали вывод результатов в текстовый файл, чтобы не приводить снимки экрана, которые занимают больше места в данном описании, чем текст. Для этого потребовались дополнительные пространства имен: System.IO и System.Text. Для простоты мы выборку значений внутренних полей класса выполнили через строковое свойство, а для вывода в поток воспользовались методом WriteLine() класса System.IO.StreamWriter. В дальнейшем иногда мы будем придерживаться именно такого подхода, чтобы иметь возможность копировать результаты в текстовом виде.
Если запустить последний пример, то появляется консольное окно, хотя вывод мы организовали в файл. Чтобы отключить появление консольного окна, установите в оболочке следующий флаг:
Project/Имя_проекта Properties/Application/Output type/Windows Application
Здесь мы отключаем появление консольного окна, но не создаем графическое окно Windows, которое нам не нужно, поскольку вывод выполняется в файл.
Иногда необходимо, чтобы метод принимал произвольное число аргументов. Для этого при объявлении метода применяется специальный параметр, который заменяет собой произвольное количество однотипных параметров. Этот параметр объявляется как массив с ключевым словом params. Он организует прием произвольного количества аргументов, в том числе и нулевое. Важно, чтобы множественный параметр при объявлении стоял последним в списке параметров метода.
Рассмотрим пример, в котором ищется минимум из произвольного числа аргументов
using System;
using System.IO;
using System.Text;
class Min
{
// Печать в статическое свойство
static String result;
public static String Result
{
get
{
return result;
}
}
public static void MinValue(params int[] nums)
{
if (nums.Length == 0)
{
result = "Нет аргументов";
return;
}
int min = nums[0];
for (int i = 1; i < nums.Length; i++)
if (nums[i] < min)
min = nums[i];
result = "Минимум равен " + min;
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Создаем и открываем поток вывода в файл
StreamWriter writeFile =
new StreamWriter(@"C:\1\xx.txt", false, ASCIIEncoding.
GetEncoding(1251));
// Вызывающий код
Min.MinValue(10, 20, 30, 40, 50);
writeFile.WriteLine(Min.Result);
Min.MinValue();
writeFile.WriteLine(Min.Result);
writeFile.Close();
}
}
Результат выполнения
Минимум равен 10 Нет аргументов
В языке C# существуют два типа переменных - типы, характеризуемые значением и ссылочные типы. Переменные типа значения содержат именованные данные, к которым относятся все числовые типы, структуры и перечисления. Они создаются при компиляции программы и размещаются в стековой области памяти при их загрузке. Ссылочные типы содержат адреса участков памяти, создаваемых динамически при выполнении программы, и представляют неименованные данные.
| Объявление типа | Создание объекта | Альтернативный синтаксис создания объекта |
|---|---|---|
| Встроенный тип, характеризуемый значением | int a; |
int a = new int(); |
Пользовательский тип, характеризуемый значением struct MyStruct
{
public x, y;
}
|
MyStruct point; |
MyStruct point = new MyStruct(); |
Пользовательский тип, характеризуемый ссылкойstruct MyClass
{
public x, y;
}
|
// Объявили ссылку MyClass point; // Создали и привязали объект point = new MyClass(); |
MyClass point = new MyClass(); |
На случай применения одинакового синтаксиса конструктор по умолчанию без параметров за типами значений зарезервирован и его переопределять нельзя. Можно только дополнить тип параметризованными конструкторами.
При выполнении операции присваивания в переменные типа значений копируются сами данные, в переменные типа ссылок копируется адрес расположения одних и тех же данных.
В C# формальные параметры метода при его объявлении называют просто параметрами, а фактические параметры, передаваемые методу при его вызове - аргументами. Статические методы и C# предлагается множество модификаторов параметров, которые обеспечивают контроль со стороны компилятора за действиями программиста при вызове этих методов и передаче им
| Модификатор | Описание |
|---|---|
| (нет) | Если параметр метода не помечен модификатором, то предполагается передача параметра по значению, т.е. в вызываемый метод передается копия оригинальных данных |
out |
Выходной параметр устанавливается вызываемым методом и передается по ссылке. Если вызываемый метод не присвоит выходному параметру значение, то генерируется ошибка компиляции |
params |
Позволяет переслать произвольное число аргументов одинакового типа в виде единого параметра. Для любого метода допускается только один модификатор params и только для последнего по порядку следования параметра |
ref |
Передается ссылка на данные клиента, которые метод может менять внутри себя. Фактически метод работает с данными, размещенными вне его |
Внутренние ( private ) методы класса обычно параметров не имеют, поскольку все объявленные в классе поля видимы внутри методов класса. Параметры нужны для общедоступных ( public ) методов, с которыми общаются клиенты класса и передают через них новые значения данных. Такие методы называются интерфейсными, включая и конструкторы.
При передаче именованного параметра он передается по значению, т.е. внутри метода создается копия подключенных данных и метод работает с этой копией. Оригинальные данные клиента метода не меняются и вызывающая сторона не увидит выполненных изменений. Это самый безопасный способ передачи, когда по исходным данным нужно получить какой-то результат, оставив сами данные без изменений.
Приведем простой пример.
using System;
static class Calculator
{
public static int Add(int x, int y, int a, int b)
{
int answer = x + y;
x = 10; y = 20; a = 30; b = 40;
return answer;
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Настройка консоли
Console.Title = "Передача параметров по значению";
Console.ForegroundColor = ConsoleColor.White;
Console.CursorVisible = false;
int x = 1, y = 2, a = 3, b = 4;
Console.WriteLine("До вызова: \tx={0}; y={1}; a={2}; b={3}",
x, y, a, b);
Calculator.Add(x, y, a, b);
Console.WriteLine("После вызова: \tx={0};
y={1}; a={2}; b={3}",
x, y, a, b);
Console.ReadLine();
}
}
Результат будет таким

Мы видим, что переприсваивание значений параметрам внутри метода не влияет на изменения данных, хранящихся в вызывающей стороне, поскольку метод работает с копиями.
Следует отметить, что когда методу передается ссылка на объект, то метод всегда работает с внешними данными, то есть с самим объектом.
Часть параметров, которым планируется внутри метода выполнить изменения значений, следует обозначать как выходные с помощью ключевого слова out. Это требуется делать и в объявлении метода, и в его вызове.
Пометим в предыдущем примере два параметра как выходные. Код будет таким
using System;
static class Calculator
{
public static int Add(int x, int y, out int a, out int b)
{
int answer = x + y;
x = 10; y = 20; a = 30; b = 40;
return answer;
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Настройка консоли
Console.Title = "Применение выходных параметров";
Console.ForegroundColor = ConsoleColor.White;
Console.CursorVisible = false;
int x = 1, y = 2, a = 3, b = 4;
Console.WriteLine("До вызова: \tx={0};
y={1}; a={2}; b={3}",
x, y, a, b);
Calculator.Add(x, y, out a, out b);
Console.WriteLine("После вызова: \tx={0};
y={1}; a={2}; b={3}",
x, y, a, b);
Console.ReadLine();
}
}
Выполним пример

Мы видим, что отмеченные как выходные параметры меняют в вызывающем коде свои значения. Им в клиенте не обязательно присваивать значения, все равно метод их изменит.
Ссылки представляют собой адреса участков памяти, где хранятся данные. Если методу передать ссылку на эту память, то он будет работать с самими данными, а не их копиями, как это происходит с передачей параметра по значению. Если ссылке не присвоить конкретный адрес перед ее передачей методу, то сгенерируется ошибка компиляции, поскольку нельзя использовать в методе неинициализированные данные, в том числе и ссылки.
Добавим в предыдущем примере в объявление и вызов первых двух параметров метода Add() модификатор ref ( reference - ссылка), заставляющий компилятор включить механизм передачи этих параметров по ссылке. Код станет таким
using System;
static class Calculator
{
public static int Add(ref int x, ref int y, out int a, out int b)
{
int answer = x + y;
x = 10; y = 20; a = 30; b = 40;
return answer;
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Настройка консоли
Console.Title = "Передача параметров по ссылке";
Console.ForegroundColor = ConsoleColor.White;
Console.CursorVisible = false;
int x = 1, y = 2, a = 3, b = 4;
Console.WriteLine("До вызова: \tx={0};
y={1}; a={2}; b={3}",
x, y, a, b);
Calculator.Add(ref x, ref y, out a, out b);
Console.WriteLine("После вызова: \tx={0};
y={1}; a={2}; b={3}",
x, y, a, b);
Console.ReadLine();
}
}
Получим результат

Метод внутри себя меняет значения данных клиента, переданных по ссылке.
Объекты ссылочного типа адресуются в программе ссылками. Их также можно передать методам по значению. Только при этом в методе создается не копия объекта, а копия ссылки ( alias - псевдоним), которая будет адресоваться к тому же объекту. Это значит, что метод будет работать с самим переданным объектом, а не с его копией. Но попытка изменить значение самого псевдонима никак не отразится на переданной из клиента ссылке - она в клиенте по-прежнему будет адресоваться к самому объекту.
using System;
class MyClass
{
// Открытые поля
public int a, b;
// Конструктор
public MyClass(int a, int b)
{
this.a = a;
this.b = b;
}
// Печать
public void Show()
{
Console.WriteLine("a={0}, b={1}", a, b);
}
}
class Start
{
static void ChangeObject(MyClass ob)
{
ob.a = 10;
ob.b = 20;
ob = null; // Изменяем копию ссылки
}
static void Main()// Вызывающая сторона
{
// Настройка консоли
Console.Title = "Передача методу объекта ссылочного типа";
Console.ForegroundColor = ConsoleColor.White;
Console.CursorVisible = false;
// Создаем объект
MyClass ob1 = new MyClass(1, 2);
Console.Write("До вызова: \t"); ob1.Show();
// Передаем методу объект в виде ссылки
ChangeObject(ob1);
Console.Write("После вызова: \t"); ob1.Show();
Console.ReadLine();
}
}
Результат будет таким

Если в метод передать ссылку на объект с модификатором ref, тогда в методе окажется адресная переменная самой ссылки (ссылка на ссылку) и смена значения этой адресной переменной изменит значение ссылки, что приведет к потере объекта или к адресации на новый объект.
using System;
static class Swap
{
public static void SwapRef(ref string str1, ref string str2)
{
string tmp = str1;
str1 = str2;
str2 = tmp;
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Настройки консоли
Console.Title = "Обмен строк через адреса";
Console.ForegroundColor = ConsoleColor.White; // Белый текст
Console.WindowWidth = 45;// Знакомест клиентской области
Console.WindowHeight = 3;// Строк клиентской области
Console.CursorVisible = false;
// Вызывающий код
string string1 = "Первая строка";
string string2 = "Вторая строка";
Console.WriteLine("До вызова: \t{0},
{1}", string1, string2);
Swap.SwapRef(ref string1, ref string2);
Console.WriteLine("После вызова: \t{0},
{1}", string1, string2);
Console.ReadLine();
}
}
Поскольку строки представляют собой объекты ссылочного типа, то метод обменивает значения ссылок, которые будут адресоваться к новым строкам.
Результат выполнения будет таким

Вот еще один пример.
using System;
using System.IO;
using System.Text;
class MyClass
{
// Печать в свойство, базового поля нет
public String Result
{
get
{
return String.Format("a={0}, b={1}", a, b);
}
}
// Закрытые поля
int a, b;
// Конструктор
public MyClass(int a, int b)
{
this.a = a;
this.b = b;
}
public static void SwapRef(ref MyClass ob1,
ref MyClass ob2, ref MyClass obNew)
{
MyClass tmp;// Объявляем вспомогательную ссылку
// Обмениваем значения ссылок
tmp = ob1;
ob1 = ob2;
ob2 = tmp;
// Создаем новый объект и прикрепляем к ссылке клиента
obNew = new MyClass(5, 6);
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Настройки консоли
Console.Title = "Обмен объектов через адреса";
Console.ForegroundColor = ConsoleColor.White; // Белый текст
Console.CursorVisible = false;
// Создаем и открываем поток вывода в файл
StreamWriter writeFile =
new StreamWriter(@"C:\1\xx.txt", false,
ASCIIEncoding.GetEncoding(1251));
// Вызывающий код
// Создаем объекты
MyClass ob1 = new MyClass(1, 2);
MyClass ob2 = new MyClass(3, 4);
// Создаем ссылку без объекта
MyClass ob3 = null;
writeFile.WriteLine("До вызова: ");
writeFile.WriteLine(ob1.Result);
writeFile.WriteLine(ob2.Result);
writeFile.WriteLine();
// Передаем методу объект в виде ссылки
MyClass.SwapRef(ref ob1, ref ob2, ref ob3);
writeFile.WriteLine("После вызова: ");
writeFile.WriteLine(ob1.Result);
writeFile.WriteLine(ob2.Result);
writeFile.WriteLine(ob3.Result);
writeFile.Close();
}
}
Результат выполнения будет размещен в автоматически созданном текстовом файле с нашим именем xx.txt и будет таким
До вызова: a=1, b=2 a=3, b=4 После вызова: a=3, b=4 a=1, b=2 a=5, b=6
В последнем приведенном коде мы немножко отвлеклись от темы и сделали вывод результатов в текстовый файл, чтобы не приводить снимки экрана, которые занимают больше места в данном описании, чем текст. Для этого потребовались дополнительные пространства имен: System.IO и System.Text. Для простоты мы выборку значений внутренних полей класса выполнили через строковое свойство, а для вывода в поток воспользовались методом WriteLine() класса System.IO.StreamWriter. В дальнейшем иногда мы будем придерживаться именно такого подхода, чтобы иметь возможность копировать результаты в текстовом виде.
Если запустить последний пример, то появляется консольное окно, хотя вывод мы организовали в файл. Чтобы отключить появление консольного окна, установите в оболочке следующий флаг:
Project/Имя_проекта Properties/Application/Output type/Windows Application
Здесь мы отключаем появление консольного окна, но не создаем графическое окно Windows, которое нам не нужно, поскольку вывод выполняется в файл.
Иногда необходимо, чтобы метод принимал произвольное число аргументов. Для этого при объявлении метода применяется специальный параметр, который заменяет собой произвольное количество однотипных параметров. Этот параметр объявляется как массив с ключевым словом params. Он организует прием произвольного количества аргументов, в том числе и нулевое. Важно, чтобы множественный параметр при объявлении стоял последним в списке параметров метода.
Рассмотрим пример, в котором ищется минимум из произвольного числа аргументов
using System;
using System.IO;
using System.Text;
class Min
{
// Печать в статическое свойство
static String result;
public static String Result
{
get
{
return result;
}
}
public static void MinValue(params int[] nums)
{
if (nums.Length == 0)
{
result = "Нет аргументов";
return;
}
int min = nums[0];
for (int i = 1; i < nums.Length; i++)
if (nums[i] < min)
min = nums[i];
result = "Минимум равен " + min;
}
}
class Start
{
static void Main()// Вызывающая сторона
{
// Создаем и открываем поток вывода в файл
StreamWriter writeFile =
new StreamWriter(@"C:\1\xx.txt", false, ASCIIEncoding.
GetEncoding(1251));
// Вызывающий код
Min.MinValue(10, 20, 30, 40, 50);
writeFile.WriteLine(Min.Result);
Min.MinValue();
writeFile.WriteLine(Min.Result);
writeFile.Close();
}
}
Результат выполнения
Минимум равен 10 Нет аргументов
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.