Laden...

Was bedeutet "xyz.Value" bei nullable Types?

Letzter Beitrag vor 9 Jahren 21 Posts 2.859 Views
Thema geschlossen
Was bedeutet "xyz.Value" bei nullable Types?

Hallo zusammen,

ich bin gerade beim Thema Nullable Types und habe dazu mal eine Frage.

Strings können ja z.B. null annehmen.

int, bool, double können null nicht annehmen.

Somit schreibe ich dann z.B.

int? test = null;

Jetzt kann ich also abfragen

if (test == null){ };

Wozu aber brauche ich

test.value;

???

Beispiel:

int? test = null;
test = 1;

Console.WriteLine(test);

Verstehe also abolut nicht was ich mit

variablenname.value;

anfangen soll?

Kann mir das vielleicht jemand kurz erklären?

Wäre toll! 😃

DANKE!

Aus Nullable Types (C# Programming Guide)

The Value property returns a value if one is assigned. Otherwise, a System.InvalidOperationException is thrown.

Verstehe ich leider überhaupt nicht!

Zwischen den Beiträgen von Coffeebean und Dir liegen 3 Minuten.
Hast Du Dir wirklich in 3 Minuten den Artikel durchgelesen und ausprobiert? Das bezweifle ich leider.

Wenn Dir jemand einen Link zum durchlesen gibt, dann meistens nicht umsonst.
Probiers doch einfach mal selber aus...? Deswegen nennt sich der Job "Entwickler".

Ich habe mich schon Stunden mit der Thematik auseinandergesetzt und wollte keinen Link haben, den ich leider auch schon kenne!

Im Buch steht es auch so und probiert habe ich auch!

Ich frage nicht einfach weil ich zu faul bin etwas auszuprobieren, sondern weil ich einfach nicht wirklich kapiere was der Sinn ist.

Aber inzwischen habe ich schonmal verstanden dass es einen Fehler gibt, wenn der Wert null ist und ich versuche mit variablenname.value; drauf zuzugreifen.

Jetzt frage ich mich nur, wieso ich nicht einfach mit variablenname drauf zugreife.

Vielleicht kann mir einfach mal jemand erklären wozu das nützlich ist!

Das steht eigentlich relativ deutlich in dem Text:
Es gibt Zustände, bei dem man Nullable braucht, zB wenn Du nicht garantieren kannst, dass es einen entsprechend passenden Rückgabewert oder überhaupt einen Wert gibt.

Du wirst in üblichen Quellcodes .Value kaum finden, sondern eher das, was ebenfalls in dem Link steht:

Use the ?? operator to assign a default value that will be applied when a nullable type whose current value is null is assigned to a non-nullable type, for example int? x = null; int y = x ?? -1;

Der übliche Use Case ist doch wohl:


if (x.HasValue) // bzw. (x != null)
{
  int y = x.Value;
}
else
{
  // no value
}

Irgendwie möchte man ja doch an den Wert herankommen, den man dort gesetzt hat. 🤔

Int32? x = GetFromAnySource();

Int32 y = x ?? 0;

würde ich als geläufig bezeichnen.
Man kann natürlich beides verwenden; aber wie gesagt: zumindest ich habe noch keinen Source mit HasValue gesehen.

Ich schon, haufenweise.

Denn manchmal muss man im NULL fall dann etwas anderes machen als einfach nur einen Defaultwert zu benutzen.

Selbst dann schätze ich die Verwendung von x != null als gebräuchlicher ein.


if(x.HasValue)

wäre dann mW best practice.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

  
if(x.HasValue)  
  

wäre dann mW best practice.

Was daran aber besser ist als


if (x != null)

bzw. für welche Fälle die erste Konstruktion besser ist, bleibt ungeklärt. Und ich denke, das war die eigentliche Frage oder nicht?
Am ehesten fällt mir noch ein, dass man x.Value in einer try-catch-Konstruktion verwenden kann, wenn man einen Grund hat, eine Exception der Abfrage vorzuziehen. Z.B. wenn x nur ausnahmsweise mal null ist. Oder wenn es um einen Wert geht, der sich zwischen Abfrage und Benutzung ändern könnte.

Die Lesbarkeit ist besser. HasValue sagt mir auf Anhieb, dass ich ein nullable vor mir habe.

LaTino
Edit: der von der CLR generierte Code ist am Ende der gleiche. Also geht's bei der Syntax tatsächlich nur um Verständlichkeit.

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

Das ist ehrlich gesagt etwas an den Haaren herbei gezogen.
Erst beim tatsächlichen Zugriff mit Hilfe von .Value wird einem klar, dass es ein Nullable ist.
Ansonsten erkennst Du am reinen Variablen-Namen absolut gar nicht, ob es sich um ein Nullable handelt oder nicht; jedenfalls wenn Du Dich an die Namenskonventionen hälst.

Da man sich i.d.R. an != null durch Objekt-Expressions gewöhnt hat kann man das ruhig auch so nutzen.
Es gibt kein Best Prastice mit .HasValue, ganz einfach, da es "genau" das gleiche ist.

Genau das gleiche im Sinne dessen, dass Nullable<T> nur auf structs anwendbar ist, es hier kein Zustand null gibt und bei im Konstruktoraufruf einfach hart HasValue = true gesetzt wird.
Der CLR Code ist auch nicht der gleiche. Das Resultat am Ende sehr wohl.

Nullable wrapped einen Werttypen so, dass er null werden kann. Eine Abfrage HasValue macht daher rein von der Syntax her klar, dass dieses Objekt auch KEINEN Wert haben kann. In C# wird empfohlen, Typen so zu behandeln, dass ihre Art deutlich wird. Daher ist HasValue in diesem Fall "besser" als != null, weil es impliziert, dass es sich um einen Wert handelt, der null sein kann, obwohl er das "sonst" nicht ist.

Und ich finde es sehr schön, dass du so überzeugt bist, wage aber dennoch eine Korrektur.

Laut C# Language Spec, v. 5 (andere habe ich nicht auf die Schnelle griffbereit) wird der Nullvergleich:


if(x != null)

implizit umgewandelt in


if(x.HasValue)

7.10.9 Equality operators and null
The == and != operators permit one operand to be a value of a nullable type and the other to be the null literal, even if no predefined or user-defined operator (in unlifted or lifted form) exists for the operation.
For an operation of one of the forms
x == null null == x x != null null != x
where x is an expression of a nullable type, if operator overload resolution (§7.2.4) fails to find an applicable operator, the result is instead computed from the HasValue property of x. Specifically, the first two forms are translated into !x.HasValue, and last two forms are translated into x.HasValue.

Eine weitere Korrektur:
Nullable wird NICHT nur auf struct angewendet, sondern prinzipiell auf Werttypen, also auch auf enums.

Und eine letzte Korrektur, noch einmal aus der Spec:

For a nullable-type the default value is an instance for which the HasValue property is false and the Value property is undefined. The default value is also known as the null value of the nullable type.

Also 180° anders als von dir beschrieben wird nix hart auf IsTrue gesetzt, sondern bei der Konstruktion eines nullable ist der defaultwert für HasValue False, was die null darstellt. Dieser Wert ändert sich bei der Initialisierung.

Insofern ist da nichts an den Haaren herbeigezogen.

LaTino

EDIT: moah, Quelle vergessen, sorry, sorry, sorry 🤔

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

Also 180° anders als von dir beschrieben wird nix hart auf IsTrue gesetzt

 public struct Nullable<T> where T : struct
    {
        private bool hasValue; 
        internal T value;
 
        [System.Runtime.Versioning.NonVersionable]
        public Nullable(T value) {
            this.value = value;
            this.hasValue = true;
        }        

Dieser Wert ändert sich bei der Initialisierung.

bei im Konstruktoraufruf einfach hart HasValue = true gesetzt wird.

Manchmal verwirrst du mich. Was du dort zitierst, ist doch genau was ich schrieb: Bei der Initialisierung wird HasValue auf true gesetzt. Der Defaultwert ist aber false, das kann auch gar nicht anders sein, weil HasValue ein bool ist, und der default von bool ist nunmal false.

Das einzige, wie ich mir erklären kann, wieso du das postest, wäre, dass du nicht weisst, was der Unterschied zwischen Konstruktion und Initialisierung bei parameterisierten Konstruktoren ist, aber das halte ich auch für unwahrscheinlich. Deshalb vermutlich ein Missverständnis, was weiss ich.

Aber wir driften bei dieser (zugegebenermaßen etwas sinnfreien, wenn auch interessanten Theorie-)Diskussion etwas vom Thema ab.

HasValue kann man benutzen, um, wie ich oben schrieb, klarzumachen, dass ich eine Variable habe, die eigentlich nicht null sein kann, es aber wegen Nullable ist.

!= null kann man benutzen, um ein Objekt mit Hilfe von Nullable so zu behandeln wie Referenztypen, auch, wenn sie es nicht sind.

Zweiteres wird zur Laufzeit zu ersterem, es macht also keinen Unterschied. Und wenn's keinen Unterschied macht, kann man es halten, wie man will - Gründe gibt's, siehe oben, für beides.

Einverstanden?

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

Zusammengefasst ist der Sinn von .Value, dass du bei direkter Verwendung der Variable deren Typ (also T?) hast. Möchtest du aber den "eigentlichen" Werttyp (also T) verwenden, musst du .Value aufrufen.


int? myNullable = 3;
int myInt = myNullable; //Fehler!
int myInt2 = myNullable.Value; //OK, falls != null. Sonst Exception.

int myInt3;
if(myNullable.HasValue)
{
myInt3 = myNullable.Value;
}

Aber das könnte man alles in der Doku usw. nachlesen.

Nicht zu vergessen:


int? myNullable = 3;

int myInt4 = myNullable ?? 0;

Ich finde ja eure Diskussionen immer sehr interessant, weil da auch jede Menge Wissen rüber kommt. Ich würde mich aber freuen, wenn der Ton noch etwas weniger offensiv sein könnte. Herbivore hat das immer toll hingekriegt.[/color]

Herbivore hat das immer toll hingekriegt.

Halte ich für ein gerücht.
Das haben die meisten nur nicht mitbekommen weil "damals" viel eher Zensiert wurde.

Spätestens an dieser Stelle ist nun wirklich alles gesagt.

Thema geschlossen