static void Main(string[] args) {
// Создается объект и выполняется попытка вызова членов.
SomeClass с = new SomeClass();
c.PublicMethod();
с.InternalMethod();
с.ProtectedInternalMethod();
с.PrivateMethod(); // Ошибка!
с.ProtectedMethod(); //Ошибка!
с.SomeMethod(); // Ошибка!
}
Если скомпилировать эту программу, вы обнаружите, что защищенные и частные члены вне объекта не доступны.
Исходный код.Проект MemberAccess размещен в подкаталоге, соответствующем главе 3.
Типы (классы, интерфейсы, структуры, перечни и делегаты) также могут использовать модификаторы доступности, но только public или internal. Когда вы создаете общедоступный тип (public), то гарантируете, что он будет доступным для других типов как в текущем компоновочном блоке, так и во внешних компоновочных блоках. Это может оказаться полезным только тогда, когда вы создаете библиотеку программного кода (см. главу 11), но здесь мы можем привести пример использования этого модификатора доступности,
// Этот тип может использоваться любым компоновочным блоком.
public class MyClass()
Внутренний (internal) тип, с другой стороны, может использоваться только компоновочным блоком, в котором этот тип определен. Если создать библиотеку программного кода .NET, в которой будут определены внутренние типы, то компоновочные блоки, ссылающиеся на эту библиотеку (файл *.dll), не смогут увидеть эти типы, создать их экземпляры или как-то иначе взаимодействовать с ними.
Характеристикой доступности, принимаемой по умолчанию для типов в C#, является internal, поэтому если вы не укажете явно ключевое слово public, то в результате будет создан внутренний тип.
// Эти классы могут использоваться только внутри
// текущего компоновочного блока.
internal class MyHelperClass{}
class FinalHelperClass{} //По умолчанию тип будет внутренним.
Замечание.В главе 4 будет говориться о вложенных типах. Вы узнаете, что вложенные типы тоже могут быть объявлены, как приватные.
Значения, назначаемые переменным по умолчанию
Членам-переменным классов автоматически присваиваются подходящие значения, предусмотренные по умолчанию. Эти значения для каждого типа данных, свои, но правила их выбора достаточно просты:
• для типа bool устанавливается значение false;
• числовым данным присваивается значение 0 (или 0.0, если это данные с плавающим разделителем);
• для типа string устанавливается значение null;
• для типа char устанавливается значение '\0';
• для ссылочных типов устанавливается значение null.
С учетом этих правил проанализируйте следующий программный код.
// Поля типа класса получают значения по умолчанию.
class Test {
public int myInt; // Устанавливается равным 0.
public string myString; // Устанавливается равным null.
public bool myBool; // Устанавливается равным false.
public object myObj; // Устанавливается равным null.
}
Значения, назначаемые по умолчанию, и локальные переменные
Совсем по-другому обстоит дело тогда, когда объявляются локальные переменные, видимые в пределах данного члена. При определении локальной переменной вы должны назначить ей начальное значение, прежде чем начать ее использование, поскольку такая перемен наяне не получает начального значения по умолчанию. Например, следующий программный код приведет к ошибке компиляции,
// Ошибка компиляции! Переменная 'localInt' должна получить
// начальное значение до ее использования.
static void Main(string[] args) {
int localInt;
Console.WriteLine(localInt);
}
Исправить проблему очень просто. Следует присвоить переменной начальное значение.
// Так лучше: теперь все довольны.
static void Main(string[] args) {
int localInt= 0;
Console.WriteLine(localInt);
}
Замечание.Правило обязательного присваивания начальных значений локальным переменным имеет одно исключение: если переменная используется в качестве выходного параметра (это понятие будет рассмотрено немного позже), то устанавливать начальное значение такой переменной не требуется.
Синтаксис инициализации членов-переменных
Типы класса обычно имеют множество членов-переменных (также называемых полями ). Если в классе можно определять множество конструкторов, то может возникнуть не слишком радующая программиста необходимость многократной записи одного и того же программного кода инициализации для каждой новой реализации конструктора. Это вполне реально, например, в том случае, когда вы не хотите принимать значение члена, предусмотренное по умолчанию. Так, чтобы член-переменная (myInt) целочисленного типа всегда инициализировался значением 9, вы можете записать следующее.
Читать дальше