Статические классы, методы, переменные. Статические конструкторы. Ключевое слово static

Статические классы, методы, переменные. Статические конструкторы. Ключевое слово static


Содержание


1. Какие элементы языка программирования C# можно объявлять статическими?

В языке программирования C# статическими могут быть:

  • классы;
  • методы;
  • переменные.

Чтобы класс (метод, переменная) был статическим, перед его объявлением ставится ключевое слово static.

 

2. Понятие статического класса. Какие особенности использования статических классов в программах на C#? Ключевое слово static

С точки зрения синтаксиса C# статический класс – это класс, который объявляется с ключевым словом static.

Общая форма объявления статического класса:

static class ClassName
{
  // поля и методы класса
  // ...
}

где ClassName – имя статического класса.

 

3. Свойства статического класса

Реализация программного кода статического класса ничем не отличается от программного кода обычного класса за исключением двух основных свойств. В сравнении с нестатическим классом, статический класс имеет следующие свойства (отличия):

  • нельзя создавать объекты статического класса;
  • статический класс должен содержать только статические члены.

 

4. Примеры, которые демонстрируют свойства статического класса

Пример 1. Пусть задан статический класс MyStaticClass. В этом классе объявляется один статический член с именем d.

// статический класс
static class MyStaticClass
{
  public static int d = 0;
}

Если попробовать создать объект статического класса

// попытка создать объект статического класса
MyStaticClass ms; // ошибка - нельзя создавать объект статического класса

то возникнет ошибка компиляции с сообщением:

Cannot declare a variable of static type 

что означает:

Невозможно объявить переменную статического типа

Пример 2. Данный пример демонстрирует правило, что статический класс должен содержать только статические члены. Пусть задан статический класс MyStaticClass. Если в статическом классе MyStaticClass попробовать объявить нестатический член d целого типа

// статический класс
static class MyStaticClass
{
  // нестатический член, без ключевого слова static
  public int d = 0; // ошибка - нельзя объявлять нестатический экземпляр в статическом классе
}

то во время компиляции компилятор выдаст следующую ошибку:

Cannot declare instance members in a static class

что значит

Нельзя объявлять члены-экземпляры в статическом классе

 

5. Примеры статических классов

Пример 1. В данном примере демонстрируется использование статической переменной в статическом классе. Объявляется статический класс с именем Count, в котором помещается одна статическая переменная count. Эта статическая переменная есть счетчиком, который совместно используется в нестатических методах Add1(), Add2() другого класса Methods.

Программный код классов Count и Methods следующий:

// статический класс Count
static class Count
{
  // статическая переменная count в классе Count - общий ресурс
  public static int count;
}

// нестатический класс
class Methods
{
  // методы нестатического класса имеют доступ
  // к статической переменной count статического класса Count
  public void Add1() // нестатический метод
  {
    // изменение значения статической переменной
    Count.count++;
  }

  public static void Add2() // статический метод
  {
    Count.count = Count.count + 2;
  }
}

В нижеследующем коде продемонстрированы обращения к переменной count класса Count и изменение значения этой переменной из методов Add1(), Add2().

Methods M = new Methods(); // создать объект класса Methods

// проверить значения статического члена
int n = Count.count; // n = 0

// вызвать нестатический метод Add1() класса Methods
M.Add1(); // увеличение Count.count на 1
n = Count.count; // n = 1

Как видно из примера, статический член данных Count.count есть общим для методов Add1(), Add2() класса Methods. Если бы в программе были реализованы другие классы с некоторыми методами, то к этому члену данных можно было бы обращаться из этих методов.

Если в данном примере класс Count объявить как нестатический (без ключевого слова static)

// класс Count - нестатический
class Count
{
  // статическая переменная count в классе Count - общий ресурс
  public static int count;
}

...

то результат работы программы не изменится. Статическую переменную Count.count можно использовать как общий ресурс.

Пример 2. Пример демонстрирует использование статического метода в нестатическом классе. Статический метод выступает общим ресурсом, который выполняет некоторую общую работу.

В примере объявляется статический метод AbsComplex(), находящий модуль комплексного числа. Метод объявляется в классе ComplexLibrary. Также объявляются 2 класса, которые содержат методы, использующие метод AbsComplex() в своих вычислениях.

// нестатический класс, содержащий статический метод
class ComplexLibrary
{
  // статический метод, вычисляет модуль комплексного числа
  // получает значение действительной (а) и мнимой (b) части комплексного числа
  public static double AbsComplex(double a, double b)
  {
    return Math.Sqrt(a * a + b * b);
  }
}

// класс, который содержит нестатический метод, использующий статический метод AbsComplex
class CalcComplex1
{
  // нестатический метод
  // определяет, равны ли модули 2 комплексных чисел
  // данный метод использует статический метод ComplexLibrary.AbsComplex() для вычислений
  public bool EqualComplex(double a1, double b1, double a2, double b2)
  {
    double value1, value2;

    // использование статического метода AbsComplex()
    value1 = ComplexLibrary.AbsComplex(a1, b1);
    value2 = ComplexLibrary.AbsComplex(a2, b2);

    return value1 == value2;
  }
}

// еще один класс, который использует метод AbsComplex() из класса ComplexLibrary
class CalcComplex2
{
  // метод, который определяет, равна ли длина комплексного числа значению 0
  public bool ZeroComplex(double a, double b)
  {
    double value = ComplexLibrary.AbsComplex(a, b);
    return value == 0.0;
  }
}

Использование методов классов CalcComplex1, CalcComplex2 может быть следующим:

CalcComplex1 c1 = new CalcComplex1(); // создать экземпляр (объект) класса
CalcComplex2 c2 = new CalcComplex2();
bool f;

f = c1.EqualComplex(3, 4, 2, 5); // f = False
f = c1.EqualComplex(1, 2, 2, 1); // f = True
f = c1.EqualComplex(-1, 2, -2, 1); // f = True
f = c2.ZeroComplex(0, 0); // f = True
f = c2.ZeroComplex(1, -5); // f = False

 

6. Какие преимущества применения статических классов, методов и переменных в программах на C#?

Статические классы, методы и переменные эффективны в следующих случаях:

  • если нужно создать так называемые методы расширения. Методы расширения используются для расширения функций класса. Эти методы являются статическими;
  • если в программе есть некоторый общий ресурс, к которому могут иметь обращение методы разных классов что обрабатывают данный ресурс (читают или изменяют его значение). Этот общий ресурс объявляется как статическая переменная. Например, таким ресурсом может быть некоторый счетчик вызовов, метод что реализует уникальную обработку, уникальная файловая переменная (ресурс) и т.п.;
  • статические классы являются эффективными, когда нужно объединить между собой группы статических методов;
  • если нужно использовать общие скрытые (private) данные класса и организовывать доступ к этим данным из статических и нестатических методов.


 

7. Чем отличается вызов статического метода от нестатического?

В любом нестатическом классе могут быть объявлены как статические методы, так и нестатические. Отличие между вызовом статического и нестатического метода класса состоит в следующем:

  • чтобы вызвать нестатический метод класса, нужно создать экземпляр (объект) этого класса. Статический метод вызывается без создания объекта класса – перед именем метода указывается имя класса, в котором этот статический метод объявлен.

Например. Задан нестатический класс Sqr, содержащий следующие два метода, которые возвращают квадрат целочисленного значения:

  • GetSqr() – нестатический метод;
  • GetSqrStatic() – статический метод.
// нестатический класс, который содержит нестатический и статический методы
class Sqr
{
  // нестатический метод
  public int GetSqr(int x)
  {
    return x * x;
  }

  // статический метод
  public static int GetSqrStatic(int x)
  {
    return x * x;
  }
}

Ниже демонстрируется вызов и использование этих методов:

// Демонстрация вызова статического и нестатического методов класса
int t;

// 1. Вызов нестатического метода класса Sqr
// Нужно создать объект класса
Sqr sc = new Sqr();
t = sc.GetSqr(7); // t = 49

// 2. Вызов статического метода класса Sqr
t = Sqr.GetSqrStatic(7); // t = 49

Как видно из вышеприведенного кода, чтобы вызвать статический метод некоторого класса, перед его именем нужно указать имя этого класса.

 

8. Можно ли объявить скрытый (private) статический член в некотором классе?

Да можно. В этом случае этот статический член класса будет доступным только в границах этого класса, то есть из методов этого класса. Доступ из методов других классов будет невозможен.

 

9. Можно ли объявлять статический член класса с модификатором доступа protected?

Да можно. В этом случае, доступ к статического члену класса будут иметь методы класса, которые унаследованы от данного класса.

Например. Задан класс A, содержащий один статический член a, который объявлен как protected. Также задан класс B, который наследует (расширяет) класс A. Из метода SomeMethod() класса B осуществляется доступ к protected-переменной класса A.

// нестатический класс, который содержит нестатический и статический методы
class A
{
  protected static int a;
}

// класс B наследует (расширяет) класс A
class B : A
{
  void SomeMethod()
  {
    a = 10; // доступ к protected-переменной класса A
  }
}

 

10. Может ли нестатический класс содержать статические переменные и статические методы?

Да может. Примеры использования статических методов в нестатическом классе приведены в пунктах 5 и 7.

 

11. Можно ли объединять статические и нестатические методы в одном классе?

Да, можно. Но только в нестатическом классе. Если класс объявлен как статический, то все методы и переменные класса должны быть также статическими (см. п. 4 — Пример 2).

Например. Пример демонстрирует объединение статического и нестатического методов класса для доступа к скрытой статической переменной t в классе. Объявляется нестатический класс CMyClass, содержащий статическую переменную, статический и нестатический методы доступа к ней.

// нестатический класс
class CMyClass
{
  // статическая переменная, объявленная как private
  private static int t;

  // статический метод, который изменяет значение статической переменной t
  public static void Set(int _t)
  {
    t = _t;
  }

  // нестатический метод, который читает значение статической переменной t
  public int Get() { return t; }
}

В нижеследующем коде продемонстрирован доступ к скрытой статической переменной t класса CMyClass

// демонстрация объединения статических и нестатических членов класса
int x;

// 1. Доступ к скрытой (private) статической переменной через статический метод Set
CMyClass.Set(777); // статическая переменная t = 777

// 2. Прочитать значение скрытой (private) статической переменной t
// 2.1. Создать объект класса
CMyClass mc = new CMyClass();

// 2.2. Вызвать нестатический метод Get() через экземпляр класса
x = mc.Get(); // x = 777 - текущее значение статической переменной

Данный пример хорошо демонстрирует, как можно организовать работу с общими, скрытыми данными класса.

 

12. Можно ли в статическом методе статического класса создать объект нестатического класса?

Да, можно. Классический пример этому, функция Main() для консольных приложений. Эта функция объявлена как static. Однако, создавать экземпляры любых нестатических классов в этой функции можно.

 

13. Что такое статические конструкторы? Пример

Статические конструкторы позволяют инициализировать статические переменные класса.

Пример. Демонстрируется объявление статического конструктора в классе.

// класс, который содержит статический конструктор
class CCount
{
  private static int count;

  static CCount()
  {
    count = 7; // инициализация статической переменной count
  }

  // доступ к внутренней статической переменной count
  public static int Get()
  {
    return count;
  }
}

Демонстрация работы класса CCount в некотором методе

int x;
x = CCount.Get(); // x = 7

 

14. Какие правила (особенности) использования статических конструкторов?

При использовании статических конструкторов нужно обратить внимание на следующие правила:

  • перед статическим конструктором может указываться ключевое слово static;
  • статические конструкторы вызываются автоматически, если класс загружается первый раз;
  • у статических конструкторов не может быть модификаторов доступа (public, private). То есть, статические конструкторы пользуются доступом по умолчанию. Это связано с тем, что статические конструкторы вызываются в классе первыми – перед созданием первого экземпляра класса в программе;
  • статический конструктор не может иметь параметров. Если попробовать создать параметризированный статический конструктор в классе, то возникнет ошибка компиляции.

 

15. Можно ли из статических конструкторов инициализировать нестатические переменные класса?

Нет, нельзя. Из статических конструкторов можно инициализировать только статические переменные этого же класса. Если в этом классе также объявляются нестатические переменные, то доступа к ним из статических конструкторов нету.

Например.

class CFileName
{
  private static string fname; // скрытая статическая переменная
  private string folder; // скрытая нестатическая переменная

  // статический конструктор
  static CFileName(string _fname)
  {
    fname = _fname; // доступ только к статическим переменным класса
    // folder = ""; // ошибка, folder - нестатическая переменная
  }
}

 


Связанные  темы