11
votes

Quelle est la raison pour laquelle tous les types de valeur ne sont pas nullables?

Y a-t-il une pénalité, de sorte que vous ne devriez que les définir comme nullable lorsque vous en avez vraiment besoin?

merci


0 commentaires

5 Réponses :


1
votes

Quels types de valeur sont réellement nullables? Je ne connais aucun.

Edit: Si vous vous référez au type de chaîne, ce n'est pas un type de valeur, mais un type de référence.


4 commentaires

Vous devez les envelopper dans le type NULLLABLE


Mais c'est quelque chose de différent alors. Je crois que le démarreur de la rubrique signifiait des types de valeur nullables hors de la boîte, faisant probablement référence au type de chaîne.


Je pense que l'op signifie quelque chose comme "si des types de valeur peuvent être nullables, pourquoi ne sont-ils pas tous nullables du début?".


Eh bien, beaucoup de programmeurs ne peuvent pas comprendre les concepts de pointeurs et de récursions, beaucoup seraient probablement confus si des types étaient tous nullables dès le début. Nullable est pour les classes avancées.



6
votes

Oui, il y a une pénalité. La structure nullable contient la valeur et également un drapeau booléen qui détermine la valeur null de la valeur.

Bien que le booléen ne soit qu'un octeen, les structures sont alignées sur des limites des mots même. Un int utilise quatre octets de mémoire, mais un int? a besoin de huit octets.


1 commentaires

La pénalité est bien pire qu'un mot supplémentaire. La conception de la structure nullable signifie que la création d'un nullable nécessitera au moins une opération supplémentaire "Copie T", et n'importe quel code qui reçoit un nullable devra effectuer au moins une opération de "copie t" supplémentaire afin de l'utiliser.



20
votes

diverses raisons:

  • Historique: nullable n'existait pas tant .net 2.0, et il ne peut pas casser le code existant - en particulier avec les différentes règles de boxe pour nullables
  • Signification: Si je veux un INT , je ne suis peut-être pas veux il est nullable ... je veux que ce soit un int , et je ne veux pas avoir à vérifier / gérer les nulls
  • espace: il ajoute des coûts supplémentaires à chaque structure ... En particulier, imaginez un octet [] , et considérez maintenant si octet a été nullable - beaucoup de frais généraux supplémentaires ; * Plus, cela vous empêcherait de faire blits etc *
  • performance: nullable ajoute beaucoup de sanctions supplémentaires; En particulier, beaucoup d'appels cachés à .hasvalue et .value / .gevalueordfault () ; Ceci est indiqué en particulier dans les "opérateurs levés" - c'est-à-dire x + y devient quelque chose comme ci-dessous, qui ajoute des boucles serrées, etc.

    (x.hasvalue && y.hasvalue)? (x.gevalueordfault () + y.gevalueordordfault ()): null

    De même, x == y doit vérifier:

    • si Null => vrai
    • si un null => faux
    • Utilisez sinon utiliser == sur getvalueordfault () de chaque

      lots de frais généraux ....


6 commentaires

N'oubliez pas d'extra ?? opérateur, ils l'ont jeté aussi. int i = j ?? k; // Si j est null, utilisez k.


Eh bien, ce n'est pas spécifique au nullable - mais un autre point bon


@Chris fait ce travail du tout? J ne peut pas être null, sinon vous ne pouvez pas l'affecter à un type de valeur, non? ;-)


@Erik - il peut si j est nullable (c'est-à-dire int? ) et k est non nullable (c.-à-d. int )


Et vous serez foutu si vous utilisez des rayons de référence!


@Leppie - cela signifie tout type de valeur (non Boxed), bien que



0
votes

En plus de Marc Gravell Répondre, vérifiez le code reflété de NULLABLABLE :

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;
    }
}


0 commentaires

0
votes

Considérez la mise en œuvre. Un entier en C # est défini comme xxx

une structure est stocké directement sur la pile, par opposition aux références d'objets qui sont des pointeurs à la mémoire (la référence elle-même est dans la pile, mais la répartition est Dans la pile).

Une référence null signifie simplement que le pointeur de la pile n'a pas été initialisé à un emplacement dans le tas.


0 commentaires