Статические члены и члены экземпляра
Члены класса являются либо статическими членами, либо членами экземпляра. В общем случае считается, что статические члены принадлежат к типам классов, а члены экземпляра принадлежат к объектам (экземплярам типов классов).
Когда объявление поля, метода, свойства, события, оператора или конструктора содержит модификатор static, оно объявляет статический член. Кроме того, объявление константы или типа неявно объявляет статический член. Статические члены имеют следующие особенности.
· Если на статический член M ссылается в доступе члена (§7.6.4) формы E.M, E должен обозначать тип-контейнера M. Обозначение E экземпляром является ошибкой времени компилирования.
· Статическое поле идентифицирует только одно место хранения для всех экземпляров данного закрытого типа класса. Независимо от количества создаваемых экземпляров данного закрытого типа класса всегда существует только одна копия статического поля.
· Статическая функция-член (метод, свойство, событие, оператор или конструктор) не выполняет операций с конкретным экземпляром. При использовании зарезервированного слова this в подобной функции-члене возникает ошибка компиляции.
Если объявление поля, метода, свойства, события, индексатора, конструктора или деструктора не включает модификатор static, оно объявляет член экземпляра. (Член экземпляра иногда называется нестатическим членом). Члены экземпляра имеют следующие особенности.
· Когда на член экземпляра M ссылаются в доступе члена (§7.6.4) формыE.M, E должен обозначать экземпляр тип-контейнера M. Обозначение E типом является ошибкой времени привязки.
· Каждый экземпляр класса содержит отдельный набор всех полей экземпляра класса.
· Член функции экземпляра (метод, свойство, индексатор, конструктор экземпляра или деструктор) работает на заданном экземпляре класса, и данный экземпляр может быть вызван в качестве this (§7.6.7).
В следующем примере представлены правила доступа к статическим членам и членам экземпляров.
class Test
{
int x;
static int y;
void F() {
x = 1; // Ok, same as this.x = 1
y = 1; // Ok, same as Test.y = 1
}
static void G() {
x = 1; // Error, cannot access this.x
y = 1; // Ok, same as Test.y = 1
}
static void Main() {
Test t = new Test();
t.x = 1; // Ok
t.y = 1; // Error, cannot access static member through instance
Test.x = 1; // Error, cannot access instance member through type
Test.y = 1; // Ok
}
}
Метод F указывает, что в члене функции экземпляра простое имя (§7.6.2) может использоваться для доступа к членам экземпляров и статическим членам. Метод G указывает, что вызов члена экземпляра через простое имя в статическом члене функции является ошибкой времени компилирования. Метод Main указывает, что в доступе члена (§7.6.4) члены экземпляра должны вызываться через экземпляры, а статические члены должны вызываться через типы.
Вложенные типы
Тип, объявленный в рамках объявления класса или структуры, называется вложенным типом. Тип, объявленный в рамках единицы компиляции или пространства имен, называется невложенным типом.
В этом примере
using System;
class A
{
class B
{
static void F() {
Console.WriteLine("A.B.F");
}
}
}
В этом примере класс B является вложенным типом, так как он объявлен в рамках класса A, а класс A является невложенным типом, так как он объявлен в рамках единицы компиляции.
Полные имена
Полным именем (§3.8.1) для вложенного типа является S.N, где S является полным именем типа, в котором объявлен тип N.
Объявленная доступность
Невложенные типы могут иметь объявленную доступность public или internal, по умолчанию используется internal. Вложенные типы тоже могут иметь эти виды объявленной доступности, плюс один или более видов объявленной доступности, в зависимости от того, является ли тип-контейнер классом или структурой.
· Вложенный тип, объявленный в классе, может иметь любой из пяти видов объявленной доступности (public, protected internal protected, internal или private), подобно другим членам класса, в нем по умолчанию используется private.
· Вложенный тип, объявленный в структуре, может иметь любой из трех видов объявленной доступности (public, internal или private), подобно другим членам структуры, в нем по умолчанию используется объявленная доступность private.
Пример:
public class List
{
// Private data structure
private class Node
{
public object Data;
public Node Next;
public Node(object data, Node next) {
this.Data = data;
this.Next = next;
}
}
private Node first = null;
private Node last = null;
// Public interface
public void AddToFront(object o) {...}
public void AddToBack(object o) {...}
public object RemoveFromFront() {...}
public object RemoveFromBack() {...}
public int Count { get {...} }
}
В этом примере объявляется частный вложенный класс Node.
Скрытие
Вложенный тип может скрывать (§3.7.1) базовый член. В объявлениях вложенных типов разрешен модификатор new, так что скрытие можно выразить явно. Пример:
using System;
class Base
{
public static void M() {
Console.WriteLine("Base.M");
}
}
class Derived: Base
{
new public class M
{
public static void F() {
Console.WriteLine("Derived.M.F");
}
}
}
class Test
{
static void Main() {
Derived.M.F();
}
}
показан вложенный класс M, скрывающий метод M, определенный в Base.
Доступ this
Вложенный тип и его тип-контейнер не имеют особого отношения к доступу this (§7.6.7). В частности, this внутри вложенного типа нельзя использовать для ссылки на члены экземпляра типа-контейнера. В случае, если вложенному типу требуется доступ к членам экземпляра типа-контейнера, доступ может быть выполнен предоставлением this для экземпляра типа-контейнера в качестве аргумента конструктора для вложенного типа. Пример.
using System;
class C
{
int i = 123;
public void F() {
Nested n = new Nested(this);
n.G();
}
public class Nested
{
C this_c;
public Nested(C c) {
this_c = c;
}
public void G() {
Console.WriteLine(this_c.i);
}
}
}
class Test
{
static void Main() {
C c = new C();
c.F();
}
}
В этом примере показан этот способ. Экземпляр C создает экземпляр Nested и передает свой собственный this конструктору Nested, чтобы предоставить последовательный доступ к членам экземпляра C.