Проектирование методов с одним и тем же именем является частью стиля программирования на С++ и стиля C#. Существование в классе методов с одним и тем же именем называется перегрузкой, а сами одноименные методы называются перегруженными.
Перегрузка методов полезна, когда требуется решать подобные задачи с разным набором аргументов. Типичный пример - это нахождение площади треугольника. Площадь можно вычислить по трем сторонам, по двум углам и стороне, по двум сторонам и углу между ними и при многих других наборах аргументов. Считается удобным во всех случаях иметь для метода одно имя, например Square, и всегда, когда нужно вычислить площадь, не задумываясь, вызывать метод Square, передавая ему известные в данный момент аргументы.
Перегрузка характерна и для знаков операций. В зависимости от типов аргументов, один и тот же знак может выполнять фактически разные операции. Классическим примером является знак операции сложения +, который играет роль операции сложения не только для арифметических данных разных типов, но и выполняет конкатенацию строк.
Уникальной характеристикой перегруженных методов является их сигнатура. Перегруженные методы, имея одинаковое имя, должны отличаться либо числом аргументов, либо их типами, либо ключевыми словами (заметьте: с точки зрения сигнатуры, ключевые слова ref и out не отличаются). Уникальность сигнатуры позволяет вызвать требуемый перегруженный метод.
Выше уже были приведены четыре перегруженных метода с именем A, различающиеся по сигнатуре. Эти методы отличаются типами аргументов и ключевым словом params. Когда вызывается метод A с двумя аргументами, то, в зависимости от типа, будет вызываться реализация без ключевого params. Когда же число аргументов больше двух, то работает реализация, позволяющая справиться с заранее не фиксированным числом аргументов. Заметьте, эта реализация может прекрасно работать и для случая двух аргументов, но полезно иметь частные случаи для фиксированного набора аргументов. При поиске подходящего перегруженного метода частные случаи получают предпочтение в сравнении с общим случаем.
1. В процедуру достаточно передавать только сам объект - массив. Все его характеристики (размерность, границы) можно определить, используя свойства и методы этого объекта.
2. Когда массив является выходным аргументом процедуры совсем не обязательно снабжать ключевым словом ref или out (хотя и допустимо). Передача аргумента по значению в таких ситуациях так же хороша, как и передача по ссылке. В результате вычислений меняется сам массив в динамической памяти, а ссылка на него остается постоянной.
3. Процедура-функция может возвращать массив в качестве результата.
class App {
public static void PrintAr1(string name,int[,] A) {
Приведем общую процедуру, формальный аргумент которой будет принадлежать родителю всех классов-массивов, что позволит передавать массив любого класса в качестве фактического аргумента:
class App {
public static void PrintAr(string name, Array A) {
Console.WriteLine(name);
switch (A.Rank) {
case 1:
for(int i = 0; i<A.GetLength(0);i++)
Console.Write(" " + name + "[{0}]={1}", i, A.GetValue(i));
Console.WriteLine();
break;
case 2:
for(int i = 0; i<A.GetLength(0);i++) {
for(int j = 0; j<A.GetLength(1);j++)
Console.Write(" " + name + "[{0},{1}]={2}",i,j, A.GetValue(i,j));
Console.WriteLine();
}
break;
default: break;
}}
public static void TestCommonPrint() {
int[] ar1 = new int[5];
double[] ar2 ={5.5, 6.6, 7.7};
int[,] ar3 = new Int32[3,4];
CreateOneDimAr(ar1);
PrintAr("ar1", ar1);
PrintAr("ar2", ar2);
CreateTwoDimAr(ar3);
PrintAr("ar3", ar3);
}
public static void CreateOneDimAr(int[] A) {
Random rnd = new Random();
for(int i = 0; i<A.GetLength(0);i++)
A[i] = rnd.Next(1,100);
}
public static void CreateTwoDimAr(int[,] A) {
Random rnd = new Random();
for(int i = 0; i<A.GetLength(0);i++)
for(int j = 0; j<A.GetLength(1);j++)
A[i,j] = rnd.Next(1,100);
}
public static void Main() {
TestCommonPrint();
}}
Первое, на что следует обратить внимание: формальный аргумент процедуры принадлежит базовому классу Array, наследниками которого являются все массивы в CLR и, естественно, все массивы C#.
Для того чтобы сохранить возможность работы с индексами, как в одномерном, так и в двумерном случае, пришлось организовать разбор случаев. Свойство Rank, возвращающее размерность массива, используется в этом разборе.
К элементам массива A, имеющего класс Array, нет возможности прямого доступа в обычной манере - A [<индексы>], но зато есть специальные методы GetValue (<индексы>) и SetValue (<индексы>).
Ввод/вывод в C# (System.IO)
Для операций ввода-вывода служит пространство имен System.IO.
Вот краткий обзор наиболее важных классов и перечислений из этого пространства имен:
BinaryReader - позволяет читать из файла данные различных типов (целые, вещественные, логические и т. п.).
BinaryWriter - позволяет записывать в файл данные различных типов (целые, вещественные, логические и т. п.).
Directory - класс со статическими методами для работы с папками.
DirectoryInfo - класс для работы с некоторой папкой.
File - класс со статическими методами для работы с файлом.
FileInfo - класс для работы с некоторым файлом.
Path - класс для работы с файловыми путями.
Перечисление FileAttributes - атрибуты файла.
Перечисление FileMode - возможные способы открытия файла.
Перечисление FileAccess содержит константы, показывающие, открыт ли файл для чтения, записи и др.
FileSystemWatcher - класс для отслеживания изменений в файловой системе.
Перечисление NotifyFilters - параметры, по которым происходит отслеживание изменений в файловой системе.
Перечисление WatcherChangeTypes - какие изменения отслеживаются в файловой системе.