Книга: C# для профессионалов. Том II
Методы
Методы
Java и C# существенно различаются в синтаксисе и идеологии в отношении способа, которым объект образовывает методы. Это связано с одной причиной — не все параметры типа ссылочных данных передаются как ссылки и не все простые типы данных должны передаваться по значению. Имеется возможность передавать аргументы по значению, как параметр in
(это способ передачи параметров по умолчанию), по ссылке, как параметр ref
, или как параметр out
. Следующий код:
public static void Main(string[] args) {
int a = 10;
Console.WriteLine(a);
Add(a);
Console.WriteLine(a);
}
public static void Add(int a) {
a++;
}
будет создавать результат, показанный ниже, как в C#, так и в Java:
10
10
Мы передаем а
по значению, поэтому это значение не связано со значением в Main
. Следовательно, увеличение а в методе Add
не влияет на а
в Main. Используя возможность, позволяющую передавать простые типы данных как ссылки, приведенный выше код можно изменить следующим образом:
public static void Main(string[] args) {
int a = 10;
Console.WriteLine(a);
Add(ref a);
Console.WriteLine(a);
}
public static void Add(ref int a) {
a++;
}
и получить:
10
11
Чтобы использовать ссылочный параметр, надо перед типом параметра использовать ключевое слово ref
. В противоположность двум другим типам параметров параметры out
не нуждаются в инициализации, перед тем как они передаются в качестве аргументов, они используются для передачи значений назад из метода. Следующий код создаст результат 100:
public static void Main(string[] args) {
int a;
Add(out a);
Console.WriteLine(a);
}
public static void Add(out int a) {
a = 100;
}
Еще одним удачным способом в C# является сокрытие метода. Концепция сокрытия метода обсуждалась ранее в этом приложении. Она позволяет иметь такую же сигнатуру, как и у метода базового класса, не переопределяя базовый метод. Это делается с помощью ключевого слова new, которое помещается перед реализацией метода. Отметим, что, как описано ранее, отсутствие ключевого слова new
в экземпляре this
по прежнему создаст то же поведение и не будет вызывать ошибки компиляции, будет создано только предупреждение. Однако, лучше его использовать, по крайней мере для того, чтобы знать, где сталкиваются сигнатуры этих методов. Вот пример сокрытия метода:
namespace Sample {
using System;
public class SuperHider {
public string Test() {
return "parent test";
}
}
public class Hider: SuperHider {
public Hider() {
}
new public string Test() {
return "child test";
}
}
}
Следующий листинг показывает, как вызывается любая версия метода Test()
:
Rider hider = new Hider();
Console.WriteLine(hider.Test());
Console.WriteLine(((SuperHider)h).Test());
Результатом этих вызовов будет:
Child test
Parent test
Сокрытие методов существенно отличается от переопределения методов. В C# переопределение метода является явной процедурой. Это отличается от подхода Java, где переопределение является поведением по умолчанию, когда сигнатура члена суперкласса совпадает с сигнатурой в его подклассе. Чтобы переопределить метод базового класса в C#, необходимо пометить его как virtual
. К счастью нельзя просто изменить класс Hider
, что показано в данном примере:
namespace Samples {
using System; public class SuperHider {
public string Test() {
return "parent test";
}
}
public class Hider: SuperHider {
public Hider() {
}
public override string Test() {
return "child test";
}
}
}
Этот код не будет компилироваться. Надо сначала проинформировать компилятор, что указанный метод, в данном случае SuperHider.test()
, может быть переопределен классами потомками. Для этого в C# используется ключевое слово virtual
, а методы, к которым применяется этот модификатор, называются виртуальными методами. Возьмем пример подходящего способа выполнения переопределения метода:
namespace Samples {
using System;
public class SuperHider {
public virtual string Test() {
return "parent test";
}
}
public class Hider: SuperHider {
public Hider() { }
public override string Test() {
return "child test";
}
}
}
Достоинством переопределения метода является гарантия, что будет вызван самый производный метод. Взгляните на код вызова, представленный ниже, такой же код, что и в примере сокрытия метода, создает два других значения:
Hider hider = new Hider();
Console.WriteLine(hider.Test());
Console.WriteLine(((SuperHider)hider).Test());
Так как гарантировано, что всегда вызывается версия test
из Hider
, мы знаем, что компиляция и выполнение кода всегда дадут следующие результаты:
Child test
Child test
Единственное синтаксическое различие между абстрактными классами в Java и C# состоит в размещении ключевого слова abstract
. Как и в Java, определение абстрактных методов в C# делает класс абстрактным.
- 6.3.2. Процедура сбора качественных данных
- Глава 2 Табличный редактор Microsoft Excel
- «Плиточные» структуры и квазикристаллы
- 16.13 Формат сообщений MIME
- Как уразуметь свою техническую роль и придерживаться ее
- Отправка запроса
- Build a Run-Time Image for an OS Design
- Как отвечать на письма, полученные вашей организацией
- 5.1.1. Создание трехмерной модели радиатора
- Привязка к процессорам
- Клонирование по сетке ("Copy to Grid")
- Программирование для Linux. Профессиональный подход