Есть ли какое-либо наказание, так что вы должны установить их только как nullable, когда вам это действительно нужно?
Спасибо
Есть ли какое-либо наказание, так что вы должны установить их только как nullable, когда вам это действительно нужно?
Спасибо
Различные причины:
Nullable<T>
не существовало до .NET 2.0, и он не может сломать существующий код - особенно с различными правилами бокса для Nullable<T>
int
, я бы не мог хотеть его обнулять... Я хочу, чтобы он был int
, и я не хочу, чтобы check-for/handle nullsbyte[]
, и теперь рассмотрим, было ли значение byte
равно нулю - много дополнительных накладных расходов; * плюс это остановит вас делать blits и т.д. *Производительность: Nullable<T>
добавляет множество дополнительных штрафов; в частности много скрытых вызовов .HasValue
и .Value
/.GetValueOrDefault()
; это проявляется, в частности, в "снятых операторах" - т.е. x + y
становится чем-то вроде ниже, которое складывается для жестких циклов и т.д.:
(x.HasValue && y.HasValue) ? (x.GetValueOrDefault() + y.GetValueOrDefault()) : null
Аналогично, x == y
должен проверить:
==
на GetValueOrDefault()
для каждоголоты накладных расходов....
Да, есть штраф. Структура Nullable<T>
содержит значение, а также логический флаг, который определяет нулевое значение.
Хотя логическое значение - это только один байт, структуры выравниваются с четными границами слов. В int
используется четыре байта памяти, но для int?
требуется восемь байтов.
Какие типы значений фактически являются нулевыми? Я ничего не знаю.
EDIT: Если вы ссылаетесь на тип строки, то это не тип значения, а ссылочный тип.
В дополнение к ответу Марка Гравелла, проверьте отображаемый код от Nullable <T> :
public struct Nullable<T> where T: struct
{
private bool hasValue;
internal T value;
public Nullable(T value)
{
this.value = value;
this.hasValue = true;
}
public bool HasValue
{
get
{
return this.hasValue;
}
}
public T Value
{
get
{
if (!this.HasValue)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NoValue);
}
return this.value;
}
}
public T GetValueOrDefault()
{
return this.value;
}
public T GetValueOrDefault(T defaultValue)
{
if (!this.HasValue)
{
return defaultValue;
}
return this.value;
}
public override bool Equals(object other)
{
if (!this.HasValue)
{
return (other == null);
}
if (other == null)
{
return false;
}
return this.value.Equals(other);
}
public override int GetHashCode()
{
if (!this.HasValue)
{
return 0;
}
return this.value.GetHashCode();
}
public override string ToString()
{
if (!this.HasValue)
{
return "";
}
return this.value.ToString();
}
public static implicit operator T?(T value)
{
return new T?(value);
}
public static explicit operator T(T? value)
{
return value.Value;
}
}
Вы заметите существование логического HasValue
и того, как его используют свойства.
Рассмотрим реализацию. Целое число в С# определяется как
public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<int>, IEquatable<int>
Структура хранится непосредственно в стеке, в отличие от ссылок на объекты, которые являются указателями на память (сама ссылка находится в стеке, но выделение находится в стеке).
Ссылка NULL просто означает, что указатель в стеке не был инициализирован в папку в куче.