Типы, допускающие значения null

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

Это семантически вовсе не то же самое, как если сказать, что значение равно 0. Семантически переменная, установленная в null, не имеет значения — даже значения 0.

В отношении же типов значений представить семантическое значение null традиционно намного труднее. Если установить значение 0, это может означать null. Но что делать, если действительно нужно представить значение 0, а не null? Многие приемы предполагают поддержку дополнительного булевского значения, которое сопровождает значение, наподобие isNull.

Чтобы избавить от необходимости использования такого нелепого, чреватого ошибками механизма, в библиотеке базовых классов .NET предлагается тип System.Nu 11 able, применение которого демонстрируется в следующем коде, где показаны два способа использования типов, допускающих значения null:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
public class Employee
{
public Employee ( string firstName,
string lastName )  {
this.firstName = firstName;
this.lastName = lastName;
this.terminationDate = null;
this.ssn = default(Nullable<long>);
}
public string firstName;
public string lastName;
public Nullable<dateTime> terminationDate;
public long? ssn; // Сокращенная нотация
}
public class EntryPoint {
static void Main()  {
Employee emp = new Employee ( "Vasya", "Pupkin" );
emp.ssn = 1234567890;
Console.WriteLine ( "{0} {1}", emp.firstName, emp.lastName ) ;
if ( emp.terminationDate.HasValue )  {
Console.WriteLine ( "Start Date:  {0}", emp.terminationDate );
}
long tempSSN = emp. ssn ?? -1;
Console.WriteLine ( "SSN:  {0}", tempSSN );
}

В приведенном коде демонстрируются два способа объявления типа, допускающего null. Первое поле, допускающее null, внутри типа Emloyee — это terminationDate, объявленное с использованием типа System.Nullable. Второе поле, допускающее null, внутри Employee — это ssn; однако на этот раз применяется сокращенная нотация С# для типов, допускающих значения null, когда объявление типа поля дополняется вопросительным знаком.

Внутренне компилятор обрабатывает его точно так же, как объявление поля terminationDate.

Несмотря на то что явное применение Nullable требует больше клавиатурного ввода, его гораздо сложнее не заметить при чтении кода, чем вопросительный знак в конце типа поля. Всегда следует отдавать предпочтение читабельному коду перед чересчур изощренным. С другой стороны, применение сокращенного синтаксиса с вопросительным знаком вполне законно, и многим он нравится.

И последнее, о чем следует упомянуть в связи с типами, допускающими null — это выполнение присваиваний. В конструкторе Employee первым делом были присвоены значения null полям типов, допускающих null. Компилятор использует неявное преобразование для значения null, чтобы все было правильно.

В действительности, для присваивания значения полю ssn в конструкторе используется синтаксис выражения def ault, и то же самое делает компилятор, когда обрабатывает присваивание значения null полю terminationDate.

Одним из свойств Nullable является HashValue, которое возвращает true, когда допускающее null значение не равно null.Hfalse — в противном случае. Наконец, необходимо посмотреть, что означает присваивание типа, допускающего null, типу, который null, не допускает.

Например, в методе Main требуется присвоить tempSSN значение emp.ssn. Однако поскольку emp.ssn может быть null, что будет присвоено tempSSN, если так случится, что в emp. ssn не окажется значения? Здесь необходимо применить операцию объединения с null, которая обозначается ??. Эта операция позволяет назначить значение, отличное от null, которое должно быть установлено в случае, когда переменная, допускающая null, справа от знака присваивания не имеет значения.

В предыдущем примере это означает: “Установить в tempSSN значение emp.ssn, а если emp.ssn не имеет значения, то установить tempSSN равным -Iй. Вооружившись таким инструментом, очень легко представлять внутри системы значения, которые семантически могут быть null, что удобно для представления полей базы данных, допускающих значения null.

Контроль доступа к конструируемым типам

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

Например, следующий код неверен, и компилироваться не будет:

1
2
3
4
5
6
7
8
9
10
11
public class Outer
{
private class Nested
{
}
public class GenericNested<t>
{
}
private GenericNested<nested> fieldl;
public GenericNested<nested> field2; // Ошибка!
}

Проблема связана с field2. Тип Nested объявлен приватным (private), поэтому каким образом GenericNested может быть public? Разумеется, никак. Доступность конструируемых типов определяется как пересечение доступности обобщенного типа и типов, указанных в списке аргументов.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100