В чем причина, по которой не все типы значений являются обнуляемыми?

Есть ли какое-либо наказание, так что вы должны установить их только как nullable, когда вам это действительно нужно?

Спасибо

Ответ 1

Различные причины:

  • История: Nullable<T> не существовало до .NET 2.0, и он не может сломать существующий код - особенно с различными правилами бокса для Nullable<T>
  • Значение: если я хочу int, я бы не мог хотеть его обнулять... Я хочу, чтобы он был int, и я не хочу, чтобы check-for/handle nulls
  • Пробел: он добавляет дополнительные затраты для каждой структуры... в частности, представьте себе byte[], и теперь рассмотрим, было ли значение byte равно нулю - много дополнительных накладных расходов; * плюс это остановит вас делать blits и т.д. *
  • Производительность: Nullable<T> добавляет множество дополнительных штрафов; в частности много скрытых вызовов .HasValue и .Value/.GetValueOrDefault(); это проявляется, в частности, в "снятых операторах" - т.е. x + y становится чем-то вроде ниже, которое складывается для жестких циклов и т.д.:

    (x.HasValue && y.HasValue) ? (x.GetValueOrDefault() + y.GetValueOrDefault()) : null

Аналогично, x == y должен проверить:

  • если оба значения null = > true
  • если один null = > false
  • используйте == на GetValueOrDefault() для каждого

лоты накладных расходов....

Ответ 2

Да, есть штраф. Структура Nullable<T> содержит значение, а также логический флаг, который определяет нулевое значение.

Хотя логическое значение - это только один байт, структуры выравниваются с четными границами слов. В int используется четыре байта памяти, но для int? требуется восемь байтов.

Ответ 3

Какие типы значений фактически являются нулевыми? Я ничего не знаю.

EDIT: Если вы ссылаетесь на тип строки, то это не тип значения, а ссылочный тип.

Ответ 4

В дополнение к ответу Марка Гравелла, проверьте отображаемый код от Nullable <T> :

public struct Nullable&lt;T&gt; 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 и того, как его используют свойства.

Ответ 5

Рассмотрим реализацию. Целое число в С# определяется как

public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<int>, IEquatable<int>

Структура хранится непосредственно в стеке, в отличие от ссылок на объекты, которые являются указателями на память (сама ссылка находится в стеке, но выделение находится в стеке).

Ссылка NULL просто означает, что указатель в стеке не был инициализирован в папку в куче.