Управляющие операторы и методы
Сравнение значений ссылок
Существуют следующие варианты:
- ссылка может быть пустой ( ref0 == null || ref1 != null );
- разные ссылки могут быть настроены на разные объекты ( ref0 != ref1 );
- разные ссылки могут быть настроены на один объект ( ref0 == ref1 );
- четвертого не дано. Отношение "больше-меньше" в условиях управляемой памяти не имеет никакого смысла.
Свойства
Объявляемые в классе данные-члены обычно используются как переменные. Статические члены сохраняют значения, актуальные для всех объектов-представителей класса. Нестатические данные-члены сохраняют в переменных объекта информацию, актуальную для данного объекта.
Обращение к этим переменным производится с использованием точечной нотации, с явным указанием данного-члена, предназначенного для сохранения (или получения) значения.
В отличие от переменных, свойства не указывают на конкретные места хранения значений. Определение свойства в C# предполагает описание способов чтения и записи значений. Алгоритмы чтения и записи значений реализуются в виде блоков операторов, которые называются get accessor и set accessor.
Наличие accessor'ов определяет доступность свойства для чтения и записи. При обращении к значению свойства активизируется механизм чтения (управление передается в get accessor), при изменении значения активизируется механизм записи (управление передается в set accessor):
class TestClass { int xVal; // Переменная объекта. // Свойство, обслуживающее переменную объекта. // Предоставляет возможность чтения и записи значений // поля xVal. public int Xval { // Эти значения реализованы в виде блоков программного кода, // обеспечивающих получение и изменение значения поля. // get accessor. get { // Здесь можно расположить любой код. // Он будет выполняться после обращения к свойству для // прочтения значения. // Например, так. Здесь получается, // что возвращаемое значение зависит от количества // обращений к свойству. xVal++; return xVal; } set { // set accessor. // Здесь можно расположить любой код. // Он будет выполняться после обращения к свойству для // записи значения. xVal = value; } } } class Class1 { static void Main(string[] args) { // Создали объект X. TestClass X = new TestClass(); // Обратились к свойству для записи в поле Xval // значения. Обращение к свойству располагается // СЛЕВА от операции присвоения. В свойстве Xval // будет активизирован блок кода set. X.Xval = 100; // Обратились к свойству для чтения из поля Xval // значения. Обращение к свойству располагается // СПРАВА от операции присвоения. В свойстве Xval // будет активизирован блок кода get. int q = X.Xval; } }Листинг 3.6.
Поскольку объект для доступа к данным Get концептуально равнозначен чтению значения переменной, хорошим стилем программирования считается отсутствие заметных побочных эффектов при использовании объектов для доступа к данным Get.
Значение свойства не должно зависеть от каких-либо обстоятельств, в частности, от количества обращений к объекту. Если доступ к свойству порождает (как в нашем случае) заметный побочный эффект, свойство рекомендуется реализовывать как метод.
Main в классе. Точка входа
Без статической функции (метода) Main невозможно построить выполняемую программу. Без явно обозначенной точки входа сборка не может выполняться.
В сборке можно помещать несколько классов. Каждый класс располагает собственным набором методов. В каждом классе могут находиться одноименные методы. В следующем примере объявляются три класса в одном пространстве имен. В каждом классе объявляется независимая точка входа и три (!) СТАТИЧЕСКИЕ функции Main (возможно и такое). Здесь главная проблема – при компиляции надо явным образом указать точку входа.
- Это можно сделать из командной строки при вызове компилятора. Например, так:
c:\ csc /main:Class1.Class3 Example1.cs
- Это можно сделать через диалог The Startup Object property среды разработки приложений, который обеспечивает спецификацию значений, явным образом НЕ ПРОПИСАННЫХ в проекте. Меню Проект – Свойства проекта, далее – General, Common Properties, <Projectname> Property Pages Dialog Box (Visual C#). В разделе Startup object надо раскрыть список классов и указать соответствующий класс.
Транслятор создаст сборку, в которой будет обеспечена передача управления соответствующей функции Main (одной из трех!):
using System; namespace Example1 { //=============================================== public class Class1 { // Спецификатор public нужен здесь. Третий класс. public class Class3 { public static void Main() { string[] sss = new string[]{Class1.s.ToString(),"12345"}; Class1.Main(sss); } } int d = 0; public static int s; static void Main(string[] args) { Class1 c1 = new Class1(); f1(c1); c1.f2(); Class2 c2 = new Class2(); //c2.f2(); c2.f3(); string[] sss = new string[] {"qwerty", c1.ToString()}; Class2.Main(sss); } static void f1(Class1 x) { //x.s = 100; s = 0; Class1.s = 125; x.d = 1; //d = 100; } void f2() { s = 0; Class1.s = 100; //this.s = 5; //Class1.d = 125; this.d = 100; d = 100; } } //=============================================== class Class2 { int d; static int s; public static void Main(string[] args) { Class1.Class3.Main(); Class2 c2 = new Class2(); f1(c2); c2.f2(); //Class1.Main(); } static void f1(Class2 x) { //x.s = 100; s = 0; Class2.s = 125; x.d = 1; //d = 100; } void f2() { s = 0; Class1.s = 100; //this.s = 5; //Class1.d = 125; this.d = 100; d = 100; } public void f3() { s = 0; Class1.s = 100; //this.s = 5; //Class1.d = 125; this.d = 100; d = 100; } } //=============================================== }Листинг 3.7.
Структура также может иметь свою точку входа!
using System; namespace defConstructors { struct MyStruct { static void Main(string[] args) { Console.WriteLine("Ha-Ha-Ha"); } } }