будет создавать результат, показанный ниже, как в 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# делает класс абстрактным.
Свойства и индексаторы
Раньше методы
get
и
set
использовались для доступа к внутренним атрибутам объекта. Сегодня C# вводит концепцию аксессоров (
accessor
), которые предоставляют безопасный и гибкий способ получения внутри лих полей, Существует два типа аксессоров. Аксессор get разрешает чтение внутренних полей объекта, а аксессор set позволяет изменять значение внутреннего поля. Ключевое слово
value
представляет новое значение справа от знака равенства во время присваивания. Отсутствие соответствующего аксессора в объявлении свойства приведет к тому, что свойство будет предназначаться либо только для чтения (нет