Laden...

.net 6 - Dereferenzierung eines möglichen Nullverweises

Erstellt von LittleTester vor 2 Jahren Letzter Beitrag vor 2 Jahren 1.312 Views
L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor 2 Jahren
.net 6 - Dereferenzierung eines möglichen Nullverweises

Ich habe angefangen mein Projekt auf Basis von .net 6 neu zu entwickeln.
Ich bekomme bei folgender Zeile die Warnung:

Dereferenzierung eines möglichen Nullverweises


readonly string softwareSysteminventoryVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();

Ich habe mir den Artikel der das Thema behandelt durchgelesen, aber das Problem habe ich nicht verstanden.
Wenn ich stattdessen


readonly string softwareSysteminventoryVersion = Application.ProductVersion;

verwende ist alles OK. Wo ist den da jetzt der Unterschied? Beide male will ich eine Version auslesen.
Ich hätte mit der Verwendung von Application.ProductVersion auch kein Problem, aber in den Einstellungen von Visual Studio 2022 kann ich die Version nicht ändern. Lediglich Assembly und Dateiversion kann man anpassen. Dort habe ich jeweils auch 2.0.0.0 eingetragen. Application.ProductVersion gibt mir aber Version 1.0.0 zurück. Die Erweiterung AutoUpdater.NET die ich sehr schätze erwartet außerdem ein vierstelliges Format (X.X.X.X). Gibt also dahingehend Probleme.

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6

2.094 Beiträge seit 2012
vor 2 Jahren

Irgendwas in deiner Aufruf-Kette kann null zurück geben. Ich glaube, das war die Version-Property.
Behandle das und der Analyser ist glücklich.

Und der Unterschied zu Application.ProductVersion ist:
https://source.dot.net/#System.Windows.Forms/System/Windows/Forms/Application.cs,ddd6e2b5fca971e7
Die faken einfach die Versionsnummer.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

16.864 Beiträge seit 2008
vor 2 Jahren

Ich hab das gerade in einer WinForms .NET 6 Anwendung nachgestellt:
Einfaches Label:


    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            this.label1.Text = Application.ProductVersion;
        }
    }

Projekteigenschaften (in Visual Studio) verwendet, um die "Product Version" zu setzen, die dann in der csproj als "Version" landet:


  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
    <Version>3.3.3.3</Version>
  </PropertyGroup>

Funktioniert einwandfrei. So zeigts ja auch die Doku 🙂

Die faken einfach die Versionsnummer.

Jo, müssen sie, weil die Versionsangabe ein Pflichtfeld ist.
Wenn also der Dev nichts setzt wird automatisch 1.0.0.0 gesetzt (wie bei .NET Framework auch).

L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor 2 Jahren

Danke euch. Schon bissel umständlich, dass man die Versionsnummer so einfügen muss. Hätte man ruhig ein Feld in der GUI der Projekteigenschaften machen können, wo man auch Assembly- und Dateiversion eintragen kann. Habs jetzt über "Projektdatei bearbeiten" selbst eingefügt wie von Abt gezeigt. (Danke)

Aber aus Interesse heraus und weil es vermutlich bei anderen Gelegenheiten wieder auftreten wird. Wie behandelt man die Warnung den korrekterweise? Muss man wirklich umständlich eine Abfrage schreiben von wegen


if(Assembly-Version-Feld != leer) {
    lese aus
} else {
    feld ist leer, gibt nix auszulesen
}

Das würde ja den schönen Einzeiler kaputt machen 🙁

Außerdem finde ich es nicht 100% sauber, wenn ich einerseits die Product-Version auslese und anzeige, AutoUpdater.NET aber die Assembly-Version heranzieht. Beide Versionen können sich ja unterscheiden und dementsprechend die Fehlersuche erschweren. Was meint ihr?

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6

16.864 Beiträge seit 2008
vor 2 Jahren

Hätte man ruhig ein Feld in der GUI der Projekteigenschaften machen können, wo man auch Assembly- und Dateiversion eintragen kann. Habs jetzt über "Projektdatei bearbeiten" selbst eingefügt wie von Abt gezeigt. (Danke)

Bitte lesen.

Projekteigenschaften (in Visual Studio) verwendet, um die "Product Version" zu setzen, die dann in der csproj als "Version" landet:

Daneben ist VS nur eine IDE. Dort sind niemals alle Features als GUI verfügbar.
Niemals. Code First ist immer Prio 1.

Beide Versionen können sich ja unterscheiden und dementsprechend die Fehlersuche erschweren.

App Versions und Install Package Versions sind zwei unterschiedliche Dinge.
.NET an für sich ist auch egal, ob es einen AutoUpdater gibt oder nicht.

L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor 2 Jahren

Danke Abt. Das habe ich dann falsch verstanden. Ich dachte Paket-Version ist nur bei Veröffentlichungen beispielsweise als Nu-Get Paket von Bedeutung und hat mit der Product-Version nichts zu tun. Steht ja eigentlich auch direkt am Anfang des Abschnitts. Jetzt, wo ich den Eintrag manuell gesetzt habe sehe ich auch, dass es da übernommen wurde.

Lehrt man nicht immer und immer wieder, dass in der Programmierung Befehle eindeutig und unmissverständlich sein müssen, weil sonnst ein Ergebnis entstehen kann, das man nicht erwartet? Tolles Beispiel dafür, wenn man von ProductVersion spricht, aber die PackageVersion meint 😉 Ich meine das nicht ironisch. Ist ein sehr praxisnahes Beispiel.

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6

4.968 Beiträge seit 2008
vor 2 Jahren

Aber aus Interesse heraus und weil es vermutlich bei anderen Gelegenheiten wieder auftreten wird. Wie behandelt man die Warnung den(n) korrekterweise? ...

Dafür kannst du den Operator ?. benutzen, s.a. NULL-bedingte Operatoren „?.“ und „?[]“:


readonly string softwareSysteminventoryVersion = Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString();

Dann käme jedoch jeweils null heraus, falls einer der Ausdrücke null ist.
Du kannst es noch mit dem ??-Operator kombinieren, um einen Standard-Wert dann zu setzen (s.a. ?? und ??= (Operatoren)), z.B.


readonly string softwareSysteminventoryVersion = Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString() ?? String.Empty; // oder "0.0.0.0" oder ...

16.864 Beiträge seit 2008
vor 2 Jahren

string? nicht vergessen 🙂


readonly string? softwareSysteminventoryVersion = Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString();

L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor 2 Jahren

Also so 100%ig habe ich das mit den vielen Fragezeichen nicht verstanden. Vor allem das readonly string?.
Wenn man die Zeile so ließt sieht es so aus als ob der Entwickler selbst nicht sicher ist, ob die Zeile sinnvoll ist und das macht was man erwartet 😄.
Den Rest habe ich dann so Verstanden:
GetExecutingAssembly()? -> Ist was_auch_immer vorhanden?
GetName()? -> Ist ein Name vorhanden? (Welcher Name? Von der Anwendung? Warum sollte kein Name vorhanden sein, bzw. geht doch gar nicht ohne?)
Version? -> Ist ein Wert zur Versionierung gesetzt?

Ich habe mal versucht die beiden Felder Assemblyversion und Dateiversion leer zu lassen. Das funktioniert tatsächlich und in der Projektdatei steht auch kein Wert mehr drin. Komischerweise wird mir trotzdem die Version beim Ausführen angezeigt und zwar die, die ich zuletzt drin hatte, also 2.0.0.0. Die GUI hat sich den Wert trotzdem gemerkt. Wo sie den allerdings hernimmt ist mir noch unklar.

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6

16.864 Beiträge seit 2008
vor 2 Jahren

Naja, aber dann hast die Doku nicht gelesen bzw. die Basics nicht verstanden.

Beispiel String.

Welt ohne Nullable:
> string = kann ein Wert haben, oder nicht (null)

Welt mit Nullable:
> string = muss einen Wert haben
> string? = kann ein Wert haben, oder nicht (null)

Diese Zeile schlägt fehl


readonly string softwareSysteminventoryVersion = Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString();

Weil der Wert null sein kann, Du aber das Feld als nicht-nullable deklariert hast.
Daher muss es string? sein und nicht string - ausser Du baust ein Fallback ein, wie es Th69 gezeigt hat.

Die Fragen kannst alle selbst beantworten, wenn Du den Quellcode bzw. die Doku der Methoden liest.
Da steht wann welcher Wert zurück kommt - und wann eben null. Lesen!

Komischerweise wird mir trotzdem die Version beim Ausführen angezeigt und zwar die, die ich zuletzt drin hatte, also 2.0.0.0. Die GUI hat sich den Wert trotzdem gemerkt. Wo sie den allerdings hernimmt ist mir noch unklar.

Weil Du Dein Projekt vollständig neu bauen musst.
Der Compiler lügt nicht 😉

T
73 Beiträge seit 2004
vor 2 Jahren

Kampf dem Spaghetti Code.
Ich schlage Clean Code mäßig vor die Schreibweise mit Umbrüchen Zeilenweise zu verwenden.
Die Lesbarkeit ist besser und via Kommentare können einfach Änderungen vorgenommen werden.
(vertikalen Platz gibts ja genug...)



public readonly string softwareSysteminventoryVersion  = // for property use =>
        Assembly
        ?.GetExecutingAssembly()
        ?.GetName()
        ?.Version
        ?.ToString() 
        ?? String.Empty
        // "Version not defined!"
        ;


16.864 Beiträge seit 2008
vor 2 Jahren

Ob das wirklich unter gutes Clean Code fällt, da scheiden sich die Geister. Ich gehören zur Fraktion: sicher nicht.
Wir verwenden i.d.R. eine einzige New Line, nicht hunderte. Ist auch weit verbreitet in der Open Source Szene.


readonly string softwareSysteminventoryVersion = Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString() 
                                                    ?? String.Empty; 

Für den Rest gibts IntelliSense Support.