Использование допускающих значение NULL типов (Руководство по программированию на C#)

Допускающие значение NULL типы могут представлять все значения лежащего в их основе типа, а также значение NULL. Допускающие значение NULL типы объявляются одним из следующих способов:

System.Nullable<T> variable

-или-

T? variable

Свойство T является базовым типом для типа, допускающего значение null. T может быть любым типом значения, включая struct; он не может быть ссылочным типом.

Примером случая, когда может использоваться допускающий значение NULL тип, может служить обычная переменная логического типа, которая может иметь два значения: true и false. Обозначающего "не определено" значения не существует. Во многих программных приложениях, в первую очередь в операциях с базами данных, переменные могут иметь неопределенное состояние. Например, поле базы данных может содержать значение true или false, но мажет также вообще не содержать какого-либо значения. Аналогично, ссылочные типы могут иметь значение null, обозначающее, что они не инициализированы.

Это несоответствие может создавать дополнительную работу по программированию, приводить к использованию дополнительных переменных для хранения информации о состоянии, применению специальных значений и т.д. Модификатор типа, преобразующий тип в допускающий значения NULL, позволяет языку C# создавать переменные типа значения, обозначающие неопределенное значение.

Примеры допускающих значение NULL типов

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

int? i = 10;
double? d1 = 3.14;
bool? flag = null;
char? letter = 'a';
int?[] arr = new int?[10];

Члены допускающих значение NULL типов

Каждый экземпляр допускающего значение NULL типа имеет два общих предназначенных только для чтения свойства:

  • HasValue

    Свойство HasValue имеет тип bool. Это свойство имеет значение true, если переменная содержит определенное значение.

  • Value

    Свойство Value имеет тот же тип, что и у базового типа. Если свойство HasValue имеет значение true, то свойство Value содержит имеющее смысл значение. Если свойство HasValue имеет значение false, то доступ к свойству Value будет приводить к формированию ошибки InvalidOperationException.

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

int? x = 10;
if (x.HasValue)
{
    System.Console.WriteLine(x.Value);
}
else
{
    System.Console.WriteLine("Undefined");
}

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

int? y = 10;
if (y != null)
{
    System.Console.WriteLine(y.Value);
}
else
{
    System.Console.WriteLine("Undefined");
}

Явные преобразования

Допускающий значение NULL тип может быть приведен к обычному типу либо явным образом с помощью приведения, либо с помощью свойства Value. Примеры.

int? n = null;

//int m1 = n;      // Will not compile. 
int m2 = (int)n;   // Compiles, but will create an exception if n is null. 
int m3 = n.Value;  // Compiles, but will create an exception if n is null.

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

Неявные преобразования

Переменной допускающего значение NULL типа может быть присвоено значение NULL с помощью ключевого слова null, как показано в следующем примере:

int? n1 = null;

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

int? n2;
n2 = 10;  // Implicit conversion.

Операторы

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

int? a = 10;
int? b = null;

a++;         // Increment by 1, now a is 11.
a = a * 10;  // Multiply by 10, now a is 110.
a = a + b;   // Add b, now a is null.

Если при выполнении сравнения с допускающими значение NULL типами значение одного из таких типов равно NULL, а второй тип содержит другое значение, то результатом сравнения всегда является false, за исключением использования оператора != (не равно). Очень важно не предполагать, что если одна операция сравнения возвращает значение false, то обратная операция возвратит значение true. В следующем примере число 10 не больше и не меньше значения NULL, а также не равно ему. Значение true возвращается только в случае использования оператора num1 != num2.

int? num1 = 10;
int? num2 = null;
if (num1 >= num2)
{
    Console.WriteLine("num1 is greater than or equal to num2");
}
else
{
    // This clause is selected, but num1 is not less than num2.
    Console.WriteLine("num1 >= num2 returned false (but num1 < num2 also is false)");
}

if (num1 < num2)
{
    Console.WriteLine("num1 is less than num2");
}
else
{
    // The else clause is selected again, but num1 is not greater than 
    // or equal to num2.
    Console.WriteLine("num1 < num2 returned false (but num1 >= num2 also is false)");
}

if (num1 != num2)
{
    // This comparison is true, num1 and num2 are not equal.
    Console.WriteLine("Finally, num1 != num2 returns true!");
}

// Change the value of num1, so that both num1 and num2 are null.
num1 = null;
if (num1 == num2)
{
    // The equality comparison returns true when both operands are null.
    Console.WriteLine("num1 == num2 returns true when the value of each is null");
}

/* Output:
 * num1 >= num2 returned false (but num1 < num2 also is false)
 * num1 < num2 returned false (but num1 >= num2 also is false)
 * Finally, num1 != num2 returns true!
 * num1 == num2 returns true when the value of each is null
 */

Сравнение на равенство двух допускающих значение NULL типов, оба из которых содержат NULL, возвратит значение true.

??Оператор

Оператор ?? определяет значение по умолчанию, возвращаемое при присвоении допускающего значение NULL типа не допускающему значение NULL типу.

int? c = null;

// d = c, unless c is null, in which case d = -1. 
int d = c ?? -1;

Этот оператор может также использоваться с несколькими допускающими значение NULL типами. Примеры.

int? e = null;
int? f = null;

// g = e or f, unless e and f are both null, in which case g = -1. 
int g = e ?? f ?? -1;

Типtype

Допускающий значение NULL тип bool? может содержать три значения: true, false и null. Сведения о том, как выполняется приведение из bool? в bool, см. в разделе Практическое руководство. Безопасное приведение bool? к bool (Руководство по программированию на C#).

Допускающие значение NULL логические типы аналогичны логическим типам переменных, используемым в языке SQL. Чтобы гарантировать, что результаты & и | операторы согласованы с имеющим три значения логическим типом в SQL, предусмотрены следующие предварительно определенные операторы:

bool? operator &(bool? x, bool? y)

bool? operator |(bool? x, bool? y)

Результаты выполнения этих операторов приведены в следующей таблице:

X

y

x&y

x|y

true

true

true

true

true

false

false

true

true

null

null

true

false

true

false

true

false

false

false

false

false

null

false

null

null

true

null

true

null

false

false

null

null

null

null

null

См. также

Ссылки

Типы, допускающие значения NULL (Руководство по программированию на C#)

Упаковка-преобразование типов, допускающих значение NULL (Руководство по программированию на C#)

Основные понятия

Руководство по программированию на C#

Типы значения, допускающие Null (Visual Basic)