Обобщенные структуры
Подобно классам, структуры также могут быть обобщенными. Они очень похожи на обобщенные классы, за исключением возможности наследования. В этой статье рассматривается обобщенная структура Nullable<T>, которая определена в .NET Framework. Итак, примером обобщенный структуры в .NET Framework является Nullable<T>.
Число в базе данных и число в языке программирования имеют важное отличие в своих характеристиках, поскольку число в базе данных может быть null. Число в C# не может быть null. Проблема существует не только с базами данных, но также с отображением данных XML на типы .NET.
Это отличие часто служит источником сложностей и требует массы дополнительной работы по отображению данных. Одно из решений состоит в отображении чисел из баз данных и файлов XML на ссылочные типы, потому что ссылочные типы могут иметь значение null. Однако это также означает дополнительные накладные расходы во время выполнения.
За счет использования структуры Nullable<T> эта проблема может быть легко решена. Ниже показан фрагмент кода с упрощенной версией определения типа Nullable<T>. Структура Nullable<T> определяет ограничение, которое состоит в том, что обобщенный тип T должен быть структурой. С классами в качестве обобщенных типов преимущество минимальных накладных расходов исчезло бы, и поскольку объекты классов все равно могут быть null, то в использовании класса с типом Nullable<T> смысла нет.
Единственное дополнение к типу Т, определенное в Nullable<T>, это поле типа bool hasValue, которое определяет, установлено значение или же оно равно null. Помимо этого, обобщенная структура определяет доступные только для чтения свойства HasValue и Value, а также перегрузки некоторых операций. Перегрузка операции приведения Nullable<T> к T определена явно, так как она может генерировать исключение в случае, если hasValue равно false. Перегрузка операции для приведения к Nullable<T> определена неявно, потому что она всегда успешна:
using System; namespace ConsoleApplication1 { public struct Nullable<T> where T : struct { public Nullable(T value) { this.hasValue = true; this.value = value; } private bool hasValue; public bool HasValue { get { return hasValue; } } private T value; public T Value { get { if (!hasValue) { throw new InvalidOperationException("no value"); } return value; } } public static explicit operator T(Nullable<T> value) { return value.Value; } public static implicit operator Nullable<T>(T value) { return new Nullable<T>(value); } public override string ToString() { if (!HasValue) return String.Empty; return this.value.ToString(); } } class Program { static void Main() { Nullable<int> x; x = 4; Console.ReadLine(); } } }
В этом примере экземпляр Nullable<T> создан как Nullable<int>. Переменная х теперь может быть использована как int, т.е. ей можно присваивать значения и применять в операциях для выполнения некоторых вычислений. Такое поведение стало возможным благодаря операциям приведения типа Nullable<T>. Однако х также может быть null. Свойства HasValue и Value типа Nullable могут проверять, есть ли значение, и обращаться к нему.
Комментарии