myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns
» Datenschutzerklärung
» Impressum

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Basistechnologien und allgemeine .NET-Klassen » Hinweis: C# 8.0 nullable reference types -- Achtung vor falscher Sicherheit
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Hinweis: C# 8.0 nullable reference types -- Achtung vor falscher Sicherheit

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
gfoidl gfoidl ist männlich
myCSharp.de-Team

avatar-2894.jpg


Dabei seit: 07.06.2009
Beiträge: 6.544
Entwicklungsumgebung: VS 2019
Herkunft: Waidring


gfoidl ist offline

Hinweis: C# 8.0 nullable reference types -- Achtung vor falscher Sicherheit

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

wie vllt. bekannt ist wird mit C# 8.0 der Kampf dem  Billion Dollar Mistake Tony Hoare) angesagt. Siehe dazu  Design with nullable reference types.

Allerdings darf man sich v.a. bei öffentlichen (public) APIs nicht in falscher Sicherheit wiegen.

Diese Gefahr / Tücke will ich mit nachfolgenden simplen Beispiel demonstrieren.

C#-Code:
#nullable enable

    public class Person
    {
        public string Name { get; }

        public Person(string name) => this.Name = name;
    }
}

Für die öffentliche Klasse Person wurde das "nullable feature" explizit aktiviert*, somit könnte man meinen, dass name eben nicht null sein darf.
Das ist für diese Klasse auch korrekt**, andernfalls hätte der Parameter als string? name deklariert werden müssen um null zu erlauben.

Wenn nun ein Benutzer unserer Klasse Person Nullable nicht aktiviert hat, wie im folgenden Code

C#-Code:
    class Program
    {
        static void Main(string[] args)
        {
            var person = new Person(null);
            Console.WriteLine(person.Name.Length);
        }
    }

, so kompiliert das Programm ohne Fehler / Warnung, zur Laufzeit gibt es aber eine NullReferenceException, da nirgends validiert wurde ob das Konstruktor-Argument name ungleich Null ist.

Wäre für obigen Code Nullable auch aktiviert worden, so hätte der C#-Compiler eine Warnung / Fehler ausgegeben.
Beim Erstellen eines "public apis" können wir aber nicht davon ausgehen, dass jeder Benutzer Nullable aktiviert hat und somit können wir in die vorhin demonstrierte Falle tappen.

Somit will ich mit diesem Beitrag den Hinweis ausprechen:
Auch mit C# 8.0 Nullable müssen public api auf null validiert werden!.

D.h. eingangs erwähnte Person-Klasse ist auch in Zukunft korrekt zu schreiben:

C#-Code:
#nullable enable

    public class Person
    {
        public string Name { get; }

        public Person(string? name) => this.Name = name ?? throw new ArgumentNullException(nameof(name));
    }

Hier wurde als Typ string? angegeben, damit verdeutlicht wird dass Verwender dieser Klasse auch null dürfen.

Wäre als Typ string angegeben und der Verwender dieser Klasse hat Nullable sowie TreatWarningsAsErrors aktiviert, so ließe sich der Code mit null gar nicht kompilieren. Dies kann u.U. ein Hindernis sein. Daher bevorzuge ich (momentan***) die Variante mit string?.


* es ist auch eine Aktivierung via Projekteinstellungen möglich, ich empfehle aber die Aktivierung per Compiler-Direktive vorzunehmen, da so beim Lesen vom Code sofort ersichtlich dass "opt-in" für Nullable durchgeführt wurde.

** korrekt im Rahmen der vom Compiler durchgeführten statischen Codeanalyse, die entweder als Warnung od. bei <TreatWarningsAsErrors>true</TreatWarningsAsErrors> (in der csproj) als Fehler ausgegeben wird

*** Nullable ist noch relativ neu, daher kann es sein dass sich meine Präferenz dafür ändert und string (also ohne das Zulassen von null) die bessere Wahl ist

mfG Gü
Neuer Beitrag 03.06.2019 21:35 Beiträge des Benutzers | zu Buddylist hinzufügen
BhaaL BhaaL ist männlich
myCSharp.de-Mitglied

Dabei seit: 14.02.2008
Beiträge: 609
Entwicklungsumgebung: VS2017


BhaaL ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Interessant, ich hatte irgendwo mal gelesen dass der Plan wäre, in dem Fall die Checks/Exceptions/Contracts vom Compiler generiert werden sollen.

Kommt die NRE beim Zugriff auf person.Name.Length oder bereits beim Konstruktor-Aufruf new Person(null)?

Edit: Wies scheint hatte ich hier ein  altes Proposal für den dammit Operator im Kopf, dass im Nullable Kontext folgende Syntax erlaubt sein soll(te):

C#-Code:
#nullable enable
public static void MyFunc(string name!) { /* ... */ }

// becomes:
public static void MyFunc(string name)
{
    if (name is null) throw new ArgumentNullException(nameof(name));
    /* ... */
}

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von BhaaL am 04.06.2019 08:25.

Neuer Beitrag 04.06.2019 08:18 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
p!lle
myCSharp.de-Mitglied

avatar-3556.jpg


Dabei seit: 22.02.2007
Beiträge: 987
Entwicklungsumgebung: Visual Studio (Community) 2017


p!lle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von gfoidl:
C#-Code:
#nullable enable

Für die öffentliche Klasse Person wurde das "nullable feature" explizit aktiviert*, somit könnte man meinen, dass name eben nicht null sein darf.

Sowas verwirrt mich immer, das Feature heißt "nullable", wenn man es einschaltet aktiviert man aber eigtl. "non-nullable".
Wahrscheinlich verstehe ich wieder irgendwas nicht, aber für mich isses verdreht. verwundert
Neuer Beitrag 04.06.2019 10:28 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 12.740
Herkunft: Stuttgart/Stockholm


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Es aktiviert nullable reference types. Das Feature ist schon gut so genannt.
Neuer Beitrag 04.06.2019 11:06 Beiträge des Benutzers | zu Buddylist hinzufügen
p!lle
myCSharp.de-Mitglied

avatar-3556.jpg


Dabei seit: 22.02.2007
Beiträge: 987
Entwicklungsumgebung: Visual Studio (Community) 2017


p!lle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Okay, dann verstehe ich es nicht.
Warum darf name dann eben nicht null sein?
Neuer Beitrag 04.06.2019 11:18 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 12.740
Herkunft: Stuttgart/Stockholm


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Mit C# 8 kommt die Möglichkeit, dass Referenztypen explizit nicht mehr null sein können.
 Tutorial: Express your design intent more clearly with nullable and non-nullable reference types

Früher wusste man bei

C#-Code:
public PersonEntity Person {get;set;}

nicht, ob Person nun null ist oder nicht - es musste immer alles geprüft werden.

Mit nullable reference types kann/muss man nun explizit angeben, wenn etwas null sein kann.
Das gilt auch für string.

C#-Code:
#nullable enable
public PersonEntity Person {get;set;} // Kann nicht null sein

public PersonEntity? Person {get;set;} // Kann null sein

Das macht am Ende den Code weniger anfällig vor ReferenceExceptions.
Neuer Beitrag 04.06.2019 11:28 Beiträge des Benutzers | zu Buddylist hinzufügen
p!lle
myCSharp.de-Mitglied

avatar-3556.jpg


Dabei seit: 22.02.2007
Beiträge: 987
Entwicklungsumgebung: Visual Studio (Community) 2017


p!lle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ja, also doch richtig verstanden.
Dann wäre "non-nullable" irgendwie logischer, schließlich kann es ja nicht null sein.
Neuer Beitrag 04.06.2019 11:33 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 12.740
Herkunft: Stuttgart/Stockholm


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Nein, denn Du musst nun explizit angeben, dass es nullable ist.
Und man nennt es so, weil es opt-in ist.

non-nullable wäre nicht opt-in.
Neuer Beitrag 04.06.2019 11:53 Beiträge des Benutzers | zu Buddylist hinzufügen
p!lle
myCSharp.de-Mitglied

avatar-3556.jpg


Dabei seit: 22.02.2007
Beiträge: 987
Entwicklungsumgebung: Visual Studio (Community) 2017


p!lle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hä?

Du schreibst doch selbst:

Zitat von Abt:
C#-Code:
#nullable enable
public PersonEntity Person {get;set;} // Kann nicht null sein

D.h. es ist nicht nullable.

EDIT: einfacher und verständlicher wäre wohl ein ? für string und Co. gewesen.

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von p!lle am 04.06.2019 11:57.

Neuer Beitrag 04.06.2019 11:56 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
gfoidl gfoidl ist männlich
myCSharp.de-Team

avatar-2894.jpg


Dabei seit: 07.06.2009
Beiträge: 6.544
Entwicklungsumgebung: VS 2019
Herkunft: Waidring

Themenstarter Thema begonnen von gfoidl

gfoidl ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo p!lle,

konkret geht es um die Analogie zu  Nullable types (wie z.B. int?), daher passt der Name mit Nullable Reference Types schon.

Mit #nullable enable werden die Nullable Reference Types als optionale Erweiterung der C#-Sprache aktiviert.

Optional ist das Ganze deshalb, damit für betehenden Code keine breaking-change passiert bzw. bestehender Code auch weiterhin kompiliert ohne Warnungen / Fehler zu generieren.

mfG Gü
Neuer Beitrag 04.06.2019 13:09 Beiträge des Benutzers | zu Buddylist hinzufügen
gfoidl gfoidl ist männlich
myCSharp.de-Team

avatar-2894.jpg


Dabei seit: 07.06.2009
Beiträge: 6.544
Entwicklungsumgebung: VS 2019
Herkunft: Waidring

Themenstarter Thema begonnen von gfoidl

gfoidl ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo BhaaL,

Zitat:
Kommt die NRE beim Zugriff auf person.Name.Length oder bereits beim Konstruktor-Aufruf new Person(null)?

Das läuft ab wie bisher, also beim Zugriff auf Length, da Name null ist.

Zitat:
Wies scheint hatte ich hier ein altes Proposal ...

Das soll in Zukunft auch kommen. Allerdings weiß ich nicht wie "Zukunft" hier definiert ist.

mfG Gü
Neuer Beitrag 04.06.2019 17:45 Beiträge des Benutzers | zu Buddylist hinzufügen
CoLo
myCSharp.de-Mitglied

Dabei seit: 25.09.2009
Beiträge: 222


CoLo ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ich stimme P!lle bei.

#nullable liest sich für mich auf dem ersten Blick als #nullableValuesAreNowAllowed und nicht als
#nullableExplicit oder #nullableReferenceTypes.

Die Benennung #nullableExplicit oder #nullableReferenceTypes hätte ich wesentlich besser empfunden.
Neuer Beitrag 05.06.2019 11:44 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum
Antwort erstellen


© Copyright 2003-2019 myCSharp.de-Team | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 24.06.2019 23:55