Управляющие операторы и методы
Сравнение значений ссылок
Существуют следующие варианты:
- ссылка может быть пустой ( 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");
}
}
}