Laden...
Avatar #avatar-2894.jpg
gfoidl myCSharp.de - Team
Entwickler in der Gasmotorenbranche (nicht nur Software) Waidring Dabei seit 07.06.2009 6.911 Beiträge
Benutzerbeschreibung
FIS-Speedski (S-DH) world champion 2015 3x FIS-Speedski (S-DH) overall worldcup winner, 2008/09, 2009/10, 2012/13 5x Subaru Velocity Challenge winner, 2009, 2010, 2013, 2014, 2015 7x PopKL Verbier winner, 2009 2x, 2010 2x, 2011 2x, 2013 1x 27 victories in 69 international Speedski-races v_max = 208,333 km/h http://de.wikipedia.org/wiki/Günther_Foidl

Forenbeiträge von gfoidl Ingesamt 6.911 Beiträge

22.02.2023 - 14:16 Uhr

Hallo P.St. ,

alle x86-Systeme ersetzt werden ..., unserer Umwelt zuliebe

Kannst du diese Aussage begründen?
Ich finde "x86 ~ nicht gut für die Umwelt" etwas vereinfacht.

werde ich auf die aktuelle Version 4.8.1 migrieren

Falls schon migriert wird, so schau dir auch .NET 7 bzw. Erste Preview von .NET 8 an.
Dort ist die Unterstützung für Arm(64) wesentlich besser. Da es insgesamt, also auch für x86, Verbesserungen zu .NET Framework (4.x) gab sollte das der Umwelt auch zu liebe kommen.

mfG Gü

15.01.2023 - 11:46 Uhr

Hallo BlueSubmarine,

Es soll aber immer nur ein Task gleichzeitig laufen.

Das lässt sich i.d.R. durch andere Architekturen besser lösen, wie auch Abt erwähnt.
Z.B. mittels Channels lässt sich ein Producer/Consumer sehr effizient und einfach umsetzen.

Sollte die Anforderung dennoch "nur ein Task gleichzeitig" sein, so lässt sich das via eigenem

10.01.2023 - 10:47 Uhr

Hallo oehrle,

hast du dir die Fehlermeldung auch durchgelesen? V.a. die InnerException? Hier nochmal der Einfachheithalber:

A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. 10.38.143.27:27017

Ist also die DB erreichbar? Firewall, etc. gestattet den Zugriff? Kann z.B. via Robomongo auf die DB zugegriffen werden usw.

mfG Gü

09.01.2023 - 17:00 Uhr

Hallo oehrle,

tritt ein Fehler auf

Du bist ja nicht erst seit Kurzem beim Forum dabei und wohl auch als Entwickler tätig. Daher solltest du auch wissen dass "ein Fehler" eine sehr exakte Beschreibung vom Problem ist, bei der sich jeder sofort auskennt und zielgerichtet eine hilfreiche Antwort verfassen kann. Oder auch nicht...

mfG Gü

12.12.2022 - 20:49 Uhr

Hallo Alf Ator,

gRPC.

Schau dir das einmal an, mehr schreib ich jetzt nicht 😉

mfG Gü

21.11.2022 - 13:25 Uhr

Hallo Jonas2909,

Gibt es eine Möglichkeit eine Methode für alle Objekte aufzurufen?

Speichere alle Menschen in einer Liste, dann kannst du z.B. mit foreach über diese Liste iterieren und für jedes Menschen-Objekt die Methode aufrufen.


public class Welt
{
    private readonly List<Mensch> _menschen;

    public void BewegeAlleMenschen(/* ... */)
    {
        foreach (Mensch mensch in _menschen)
        {
            mensch.Bewege(/* ... */);
        }
    }
}

BTW: [Tipp] Anfängerhinweis == true / == false

mfG Gü

11.11.2022 - 12:17 Uhr

Hallo C4RL0,

Gibt es Frameworks ... die soetwas unterstützen ...

Ja gibt es, aber das hängt von den Rahmenbedingungen ab, also ob ein solcher Einsatz möglich ist od. nicht. Wegen

I.d.R. arbeite ich mit Windows Forms.

gibt es irgendwelche Beschränkungen, Voraussetzungen, etc. die du uns mitteilen solltest? Z.B. es muss auf einem Server in eurer Firma laufen, kann in der Cloud sein, Clients sind alle WinForms od. nicht, Datenbank muss SQL Server sein od. nicht. Usw. denn danach richten sich auch die möglichen Empfehlungen / Tipps.

Nach "workflow engines" hast du sicher schon gegooglet 😉

mfG Gü

08.11.2022 - 17:24 Uhr

Hallo,

Wobei ein Umstieg eigentlich kaum Probleme machen dürfte.

Für "normale" Anwendungen sollte es keine Problem geben, da wie immer sehr hoher Wert auf Abwärtskompatibilität gelegt wird / wurde. Ganz klappt das jedoch nicht immer, daher zeigt Breaking changes in .NET 7 eine Übersicht davon.

Hat sich ggf. noch bei der Performance mit .NET 7 geändert oder läuft noch alles gleich flink?

.NET hat ein sehr intensives Perf-Lab indem fast permanent Benchmarks laufen um eventuelle Regressionen frühzeitig entdecken zu können.
.NET 7 ist in vielen Bereichen schneller als bisherige .NET-Versionen, zumindest jedenfalls nicht langsamer. Details dazu im Link, den Abt gepostet hat.

Wichtiger finde ich jedoch die Menge an neuen APIs und C#-Möglichkeiten, die es uns allen gestatten eleganteren / effizienteren Code zu schreiben 🙂

mfG Gü

02.11.2022 - 22:55 Uhr

Hallo Little Tester ,

bekommen, also "get". Ich will die Variable dann nicht mehr verändern, weil ich ja die Information dann habe die ich brauche.

Das passt so und das Objekt ist dann "immutable", kann also nicht mehr verändert werden.
Die Werte der Eigenschaft kann im Konstruktor gesetzt werden.


public class Person
{
    public string Name { get; set; }
    public Date Birthdate { get; }

    public Person(string name, Date birthdate)
    {
        Name = name;
        Birthdate = birthdate;
    }
}

Name hat Getter und Setter, da sich der Name z.B. durch Heirat, Namensänderung ändern kann.
Birthdate kann sich aber nicht ändern, daher nur ein "Getter".
Um die Werte zu setzen, werden diese während der Konstruktion des Objects im sog. Konstruktor gesetzt.

mfG Gü

25.10.2022 - 11:21 Uhr

Hallo dr4g0n76,

Fuzzing benutz ich bei Parsern die "untrusted input" haben und von byte / char -> T gehen.
Da kann es schon sein, dass ein paar Kombinationen der Bytes (im hohen UTF-8 Bereich) dabei sind, an dene ich bei Unit-Tests nicht gedacht habe. Durch das Ergebnis einer solches Fuzz-Session wenn etwas gefunden wurde, können die Unit-Tests nachgerüstet werden.

Ich seh Fuzzing dennoch eher als Nische und nur für spezielle Anforderungen, wie eben Parser, sinnvoll an.
Wobei mit "Parser" auch das Lesen einer Befehszeile, einer Konfig gemeint sein kann. Bei diesen Beispielen würde ich aber sowieso auf die .NET Infrastruktur aufbauen und vertrauen dass es passt (dort könnte Fuzzing wiederum angewandt werden).

Der Aufwand an sich um Fuzzing zum Laufen zu bringen ist nicht recht hoch, aber die Dauer einer Fuzz-Session i.d.R. schon (etliche Stunden und mehr).
Nur bei trivialen Bugs kann der Fuzzer recht schnell einen Treffer finden -- das ist aber stochastitisch und nicht deterministisch, je nachdem welche Seed für die Mutationen, etc. verwendet wird.

Also kurz: finde ich sinnvoll, aber nur für wenige spezielle Anforderungen.

WinDbg verwende ich nicht (direkt). Wenn schon dotnet-dump und den dortigen SOS Befehlen.

mfG Gü

23.10.2022 - 11:52 Uhr

Hallo Palladin007,

Ich will den hauptsächlich als Test-Server für Projekte nutzen, aktuell immer EFCore + SQLServer

Dazu nehm ich eine lokal gehostete Linux-VM (in VirtualBox), in welcher der SQL Server als Docker-Container läuft.
Der Container damit ein sehr einfaches Reset möglich ist.
Außerdem kann so ein vom SQL Server ein eigenes Image erstellt werden, das dann u.a. für CI verwendet wird.

mfG Gü

22.10.2022 - 17:22 Uhr

Hallo Biokartoffel,

Damit öffnen sich gleich neue Ideen.

Daher gabs auch den Code, denn i.d.R. ist das Forum kein Code-Generator. Aber als Ansport / Einstieg kann und soll so ein Schnippsel dienen -- wir alle haben ja einaml begonnen 😉

mfG Gü

22.10.2022 - 16:03 Uhr

Hallo Biokartoffel,

z.B.:


Random rnd = new();

Console.WriteLine("Übungsprogramm \"Kleines 1*1\". Abbruch mit Ctrl+C");
Console.WriteLine();

const int LowerInclusive = 0;
const int UpperInclusive = 10;

while (true)
{
    int a = rnd.Next(LowerInclusive, UpperInclusive + 1);
    int b = rnd.Next(LowerInclusive, UpperInclusive + 1);

    Console.Write($"{a} * {b} = ");
    string? answer = Console.ReadLine();

    if (answer is null)
    {
        break;
    }

    if (int.TryParse(answer, out int result))
    {
        int expected = a * b;
        bool isCorrect = result == expected;

        Console.Write("Antwort ist ");
        Console.ForegroundColor = isCorrect ? ConsoleColor.Green : ConsoleColor.Red;
        Console.WriteLine(isCorrect ? "richtig" : "falsch");
        Console.ResetColor();
    }
    else
    {
        Console.WriteLine("Falsche Eingabe, eine Zahl wird erwartet.");
    }
}

Das kannst du nun beliebig ausbauen 🙂

mfG Gü

20.10.2022 - 14:47 Uhr

Hallo colophonius,

Wenn ich ein Rep öffne

Öffnest du das in einen leeren Ordner?
Dann ist der .vs-Ordner ja auch nicht da.

Wenn ich mit Projekten öfter arbeite, so sind diese lokal vorhanden und ich brauch nur per Pull / Fetch die Änderungen holen. Die lokalen Einstellungen in .vs, .suo bleiben davon unberührt.

mfG Gü

20.10.2022 - 13:28 Uhr

Hallo colophonius,

Wenn ich ein Rep öffne, muss ich jedesmal bestimmte Einstellungen erneut konfigurieren. Dazu zählen z. B. die Startprojekte.

Diese Benutzer-Einstellungen werden im .vs-Ordner im Wurzelverzeichnis des Repo gespeichert (is ein Hidden-Folder).
Dieser sollte auch nicht in die Versionskontrolle eingecheckt werden -- eben da "Benutzer-Einstellungen".
Wenn dieser beim Auschecken nicht vorhanden ist, so tritt eben das beschriebene Verhalten auf.

mfG Gü

20.10.2022 - 13:25 Uhr

Hallo ThavalUga,

die Zeichenkette muss geparst werden, dabei gehts am einfachsten mit [Artikel] Regex-Tutorial, wie z.B. ^([+-]?(?:\d+)?)(x(?:\^(\d+))?)?. Wenn du damit nicht vertraut bist, so schauts schrecklich aus, aber wenn das selbst geschrieben wird gehts recht einfach, da für jede "Gruppe" die benötigt wird ein "Block" dasteht.

Schau dir mal im Code die Methode GetPolynomCoefficients an. Dort wird per Regex ein Term gematched, dieser dann geparst und die Eingabe um diesen Term verkürzt. Mit den restlichen Termen gehts dann so weiter, bis letztlich nichts mehr übrig ist.


using System.Text.RegularExpressions;

string input = "3x^4+2x^3-x^2+x-5";

double[] coefficients = GetPolynomCoefficients(input)
    .OrderByDescending(t => t.Power)
    .Select(t => t.Coefficient)
    .ToArray();

Console.WriteLine(input);
for (int i = 0; i < coefficients.Length; ++i)
{
    double c = coefficients[i];
    Console.Write($"{(Math.Sign(c) >= 0 ? "+" : "-")}{Math.Abs(c)}");

    if (i < coefficients.Length - 2)
    {
        Console.Write($"x^{coefficients.Length - 1 - i}");
    }
    else if (i < coefficients.Length - 1)
    {
        Console.Write("x");
    }
}
Console.WriteLine();

static IEnumerable<Term> GetPolynomCoefficients(string input)
{
    // language=regex
    const string Pattern = @"^([+-]?(?:\d+)?)(x(?:\^(\d+))?)?";

    while (input.Length > 0)
    {
        Match match = Regex.Match(input, Pattern);

        if (!match.Success)
        {
            throw new Exception("Given polynom can't be parsed. Bla bla bla (more info about failure and how to recover)");
        }

        if (!TryGetCoefficient(match, out double coefficient))
        {
            throw new Exception("... (something like 'coefficient can't be parsed at index ...')");
        }

        if (!TryGetPower(match, out int power))
        {
            throw new Exception("... (something like 'power can't be parsed at index ...')");
        }

        yield return new Term(coefficient, power);

        input = input[match.Length..];
    }

    static bool TryGetCoefficient(Match match, out double coefficient)
    {
        string value = match.Groups[1].Value;

        if (value.Length == 0 || value == "+")
        {
            coefficient = 1d;
            return true;
        }

        if (value == "-")
        {
            coefficient = -1d;
            return true;
        }

        return double.TryParse(value, out coefficient);
    }

    static bool TryGetPower(Match match, out int power)
    {
        string value = match.Groups[3].Value;

        if (value.Length == 0)
        {
            if (match.Groups[2].Value.Length == 0)
            {
                power = 0;
                return true;
            }

            if (match.Groups[2].Value == "x")
            {
                power = 1;
                return true;
            }
        }

        return int.TryParse(value, out power);
    }
}

public readonly record struct Term(double Coefficient, int Power);

Ohne Regex ginge es auch, aber aufgrund der Sonderfälle wie implizit {+1, -1} als Koeffizient wird schon umständlicher. Genauso wenn die Potenz implizit {1, 0} ist.
D.h. ohne Regex würde eine Art Syntax-Baum benötigt werden und das ist wohl Overkill. BTW: das Regex-Match kann hier als Art "Mini-Syntax-Baum" gesehen werden.

mfG Gü

19.10.2022 - 12:46 Uhr

Hallo kstanger,

bei dem Thema wo es ums Verständnis geht helfen vllt. mehre Antworten mit ähnlichem Inhalt, aber verschiedenem Text 😉

Der Vollständigkeithalber: [Artikel] Drei-Schichten-Architektur

Einfache Pauschalantworten auf deinen Frage kann ich nicht geben, da es wie so oft abhängt, worum es konkret geht. Ich versuch daher verkürzt und vereinfacht zu antworten.

Wie trennt man eigentlich die 3 Schichten?

Bei kleinen Projekten: verschiedene Namespaces
Umso größer das Projekt wird, so desto eher erfolgt auch eine Aufteilung in verschiedene Projektmappen (csproj).
Möglichkeiten gibt es viele, die aber vom konkreten Fall abhängen.

Und wie verbindet man sie? z.B. über Methodenaufrufe?

Wenn alles im gleichen Prozess läuft, dann ja. Einfacher und besser geht es nicht.
Sind die Schichten über mehrere Prozesse verteilt, so wird IPC (inter process communication) benötigt und falls die Schichten gar auf mehreren Servern verteilt sind, dann eine andere Kommunikationsart.

über das Modell spricht, nicht aber über die Umsetzung.

Ich sehe dafür merhere Gründe (auch wenn ich zurück an meine Anfangszeiten denke):* Es gibt nicht "die Umsetzung" da es je nach konkreter Anforderung verschiedene Ausprägungen geben kann. Sowie es in der (Bau-) Architektur auch nicht "die Umsetzung" vom Haus gibt. Grundsätzlich schon (Keller, Parterre, Obergeschoße), aber konkrete hängt es auch hier vom Anwendungsfall ab.

  • Die 3-Schichten Architektur ist trivial -- da gibt es nicht sehr viel zu beschreiben.
    Mir gings aber auch so, dass die geistige Hürde fürs Verständnis erst einmal übersprungen werden musste. Am einfachsten gehts mit einem ganz simplen Projekt, bei dem Unit-Tests vorhanden sind, denn die Testbarkeit von Komponenten führe mehr od. weniger automatisch zum richtigen Design.

Datenzugriffsschicht = Definition der Objektlisten + Serialisierung

"Serialisierung" für was? Nimm besser ein Datenbank statt in Dateien zu Serialisieren.

mfG Gü

14.10.2022 - 10:13 Uhr

Hallo Savage,

warum verwendest du keinen Blog-Storage und greifst über den zugehörigen Client / SDK darauf zu?
Dann wäre das auch sauber getrennt und zukunftssicherer, falls die Anwendung z.B. auf serverless geändert werden sollte, etc.

Im Code jedenfalls sollte das Verwalten der Dateien ohnehin wegabstrahiert worden sein, dann sind solche Änderungen auch recht einfach durchführbar.

mfG Gü

27.09.2022 - 10:34 Uhr

Hallo shutouke,

Ich schreibe gerade ein Programm das mich an Geburtstage erinnern soll.

Statt einer CSV kannst du dafür auch eine "richtige" Datenbank verwenden. Es gibt auch Datenbanken die ohne Server auskommen (z.b. SQLite).
Dann brauchst du dich ums Sortieren beim Einfügen nicht kümmern und kann die Prüfung auf Geburtstag recht einfach per Abfrage gegen die DB durchführen.

Wenns um den Lerneffekt geht, so mach beide Varianten: CSV und DB. Da lernst du viel und kannst selbst über die Vor-/Nachteile jeder Variante sinnieren.

mfG Gü

18.09.2022 - 11:31 Uhr

Hallo Tommix,

der HashCode ist kein kryptografischer Hash des Strings (gilt für Object im Allgemeinen), sondern nur eine Art "Fingerabdruck" für den aktuellen Prozess, so dass Vergleiche und v.a. Hash-basierte Datentypen (wie Dictionary, HashSet) mit O(1)-Operationen umgesetzt werden können.

Bei int ist der HashCode trivial implementiert, nämlich der Wert einfach selbst.

Da GetHashCode als Rückgabetype int verwendet gibt es folglich auch nur soviele verschiedene HashCodes wie eben mit int abgebildet werden können (2^32 = 4.294.967.296). Also eine begrenzte Menge und das Schubfachprinzip findet Anwendung, kurz es wird Kollisionen (= gleicher HashCode) geben.

Strings sind wohl einer am häufigst verwendeten Datentypen. Web-Server und Authentifizierungserver sind hierbei keine Aussnahme.
Würde für jeden Programmablauf für den gleichen String immer der gleiche HashCode ermittelt werden, so öffnet das die Tür für Angriffe* da ein bestimmter String eine deterministische Ausgabe (hier HashCode) liefert.

Aus diesem Grund verwendet .NET seit einiger Zeit (ich glaube .NET Core 2.1, habs nicht nachgeschaut) einen zufälligen "Startwert" für String-Hashes. D.h. innerhalb eines Programmablaufs ist das Resultat von GetHashCode für gleiche Eingaben deterministisch (sonst wäre es ja unsinnig), aber für jeden Programmablauf eben anders um solche Angriiffe zu erschweren.

Wie eingangs bereits angedeutet sollte der Wert von GetHashCode ohnehin nicht von Bedeutung sein und v.a. nicht explizit verwendet werden, denn dazu ist GetHashCode nicht gedacht. Betrachte den Wert von GetHashCode als Implementierungsdetail, das für Dictionary, HashSet, EqualityComparer, etc. verwendet wird ohne dass du dich für den tatsächlichen Wert interessierst**.

* auf dem Gebiet kenn ich mich zu wenig aus um konkrete Beispiel liefern zu können.
** außer du entwickelst eine eigene Methode für GetHashCode von eigenen Typen um so eine möglichst gleichmäßige Verteiliung ohne zuviele Kollisionen zu erhalten

mfG Gü

11.08.2022 - 12:38 Uhr

Hallo theuserbl,

Das fühlt sich an wie Visual Studio - nur ohne GUI:

😉
VS verwendet (mehr od. weniger) die gleichen Build-Tools, daher ist deine Aussage schon korrekt.

  • Im Projekt-Order wird eine Visual Studio Projektdatei (MyApp.csproj) angelegt.
  • Die Binaries entstehen nicht standardmäßig wie beim alten .NET FRamework, C/C++ und Java an der Stelle, wo auch der Quellcode ist, sondern es werdem - wie bei VisualStudio - Unterordner "bin" und "obj" erstellt, die ihrerseits jeweils entweder einen Unterordner "Debug" oder "Release" haben, wo dann die Binärdateien enthalten sind.

Dass das Kompilat im gleichen Ordner landet wie die Quell-Dateien ist ein Anti-Pattern und sollte ohnehin vermieden werden.
Die Unterscheidung zwischen Debug / Release macht auch Sinn, da es dem Compiler frei steht für Release mehr Optimierungen durchzuführen.

Gängige Build-Tools anderer Sprachen / Plattformen wie z.B. CMake (hauptsächlich für C/C++) verhalten sich hier nicht anders. Statt der csproj gibt es eine / mehrere CMakeList.txt und die Ausgabe erfolgt auch in einem von der Quelle unterschiedlichen Pfad.

MsBuild (das Tool welches die csproj verarbeitet) muss du ja nicht verwenden, sondern kannst auch direkt mit CSC arbeiten. Aber ohne Build-Script (welches csproj letztlich auch ist) wird es eher schnell unhandlich.
Mit und ohne csproj kann der Ausgabe-Pfad auch konfiguriert werden -- standardmäßig werden halt Defaults verwendet, die sich in .NET so eingebürgert haben.

So ist ja das Anfangs C#-Programm eins, das eher wie aus einer Skriptsprache aussieht: Ohne Main-Methode und Klasse direkt mit dem Befehl losgelegt.

Zumindest in der VS-Projektvorlage kann die "alte Verhalten" mit class Program und static void Main wiederhergestellt werden.
Aber ich finds ohne netter, denn wozu immer wieder den unnötigen Code (generieren lassen). Der bläht ja nur auf ohne wirklichen nutzen.

Dass es aussieht wie eine Skriptsprache war in der Tat eine der Motivationen hinter dieser Änderung, denn für Einsteiger wurde es als unnötige Hürde erachtet eine Klasse und eine statische Methode zu erstellen, welche als Einstieg (ins Programm) dienen.
Wie T-Virus erwähnt ist das aber nur Compiler-Magick

mfG Gü

11.08.2022 - 11:15 Uhr

Hallo,

Da ich es nicht installieren möchte, lade ich für Windows eine zip-Datei runter.

Der Installer wird ja gerade destwegen angeboten, damit die Pfade, etc. nicht manuell gesetzt werden müssen.
Mit dem zip (ala xcopy-Deploy) kann eine bestehende Installation überschrieben werden od. man erfüllt die nötigen Vor- und Nachschritte selbst. Das ist so aber auch dokumentiert -- siehe Download and manually install.

Bitte immer Dokus lesen bevor die Schuld auf eine Technologie geschoben wird!

Kein csc.exe und kein vbc.exe .
Auch in den Unterverzeichnisssen finde ich keine Compiler.

In .NET ist seit jeher die Assembly das Binär-Produkt. Beim .NET Framework wurde eine EXE erzeugt, die im Grunde nichts anderes als der Code gepackt als DLL und zusätzlich der Loader-Teil für das Betriebssystem ist. Damit das OS das auch verwenden kann wurde es als nur als EXE "verpackt".

In .NET Core und später .NET wurde nur eine DLL erzeugt*, welche mittels dotnet MeineAnwendung.dll gestartet werden kann. dotnet ist dabei der Host und enthält u.a. den Loader-Teil fürs OS.

Im Ordner .\dotnet-sdk-7.0.100-preview.7.22377.5-win-x64.zip\sdk\7.0.100-preview.7.22377.5\Roslyn\bincore sind nun die Compiler tatsächlich vorhanden 😉
Aber nicht als EXE, sondern als csc.dll (C# Compiler) und vbc.dll (VB.NET Compiler).
Wie vorhin erwähnt, können diese via dotnet csc.dll ausgeführt werden. I.d.R. jedoch via MsBuild-Task der die Assembly lädt und direkt ausführt**.

* bei einem Framework-dependent deployment, es gibt auch weitere Möglichkeiten bei denen eine EXE direkt erstellt wird, aber das lässt sich in der Doku nachlesen

** ein wenig kompliziertes ist es mittlerweile schon, da zur Leistungssteigerung und für den Gebrauch in VS eine Art Build-Server gestartet wird, der den / die Compiler-Instanzen verwaltet

WTF??? Geht es noch komplizierter?

Ok, ich habe nun also aus dem Unterverzeichnis .\shared\Microsoft.NETCore.App die Datei hostpolicy.dll ins Hauptverzeichnis kopiert.

Obs noch komplizierter geht weiß ich nicht, aber du bist schon ganz gut dabei 😉

Mit einem Blick in die Doku (siehe oben) od. durch Verwendung des Installers hättest du weniger Frust und die Zeit, welche für deinen Beitrag hier benötigt wurde, hätte in Produktives umgesetzt werden können.

Muß man nun für jede exe-Datei zusätzlich eine json-Datei erstellen?
Beim .NET Framework war es nicht nötig.

Nein. Zum Einen geschieht dies automatisch durch die Build-Tools, zum Anderen werden diese json-Dateien bei Single-File-Deployment ebenfalls in die EXE gepackt.
.NET Framework funktioniert z.T. anders und v.a. nicht auf anderen OS als Windows. Daher sind auch andere Konzepte nötig um wirklich plattformunabhängig sein zu können.

Betrachte diese json-Dateien einfach als Teil der Build-Ausgabe. Diese stören doch nicht? Falls es es dich stört und du nur eine EXE als Ausgabe haben willst, so schau dir Single-file deployment and executable an.

mfG Gü

05.08.2022 - 18:44 Uhr

Hallo Sw4t,

für Komplettheit: Math.Min ist eine Methode in .NET für das Minimum von 2 Werten.

mfG Gü

20.07.2022 - 13:02 Uhr

Hallo sandreas,

ich finde die StreamLimiter Klasse ist weder Teig noch Mehl. Irgendwie wird der _innerStream beschränkt, dann aber doch nicht so ganz konsequent.
Z.B. Position gibt diese vom _innerStream an.

So einen Typen würde ich eher SubReadStream nennen, der eine "View" über den _innerStream legt, dabei zu Beginn von Außen Offset := 0 und Länge := das Limit ist.
Intern kann das ja auf den _innerStream umgerechnet werden. Z.B. beim Setzen der Position halt den Offset berücksichtigen.

Beim Lesen, egal ob die byte[] od. Span<byte>-Überladung, ist count bzw. der buffer (bei Span-Überladung) entsprechend zu verkleinern, falls über das Limit hinaus gelesen würde.

Für den Verwender sollte dieser Stream jedenfalls nur den nutzbaren Teil (~ "View") widerspiegeln.

mfG Gü

19.07.2022 - 17:38 Uhr

Hallo sandreas,

Man kann da bestimmt wieder einiges falsch machen, wenn man die interna von Stream nicht genau kennt.

Warum? Es ist hier doch nur einfache Addition (wieviel schon gelesen wurde) und ein Vergleich mit der Soll-Länge?! KISS -- vermutlich hast du dich gedanklich in einem zu komplizierten Weg verrannt.

Die Interna von Stream (der Basisklasse) sind nicht sehr schwierig, v.a. bei Read. Man übergibt einen Buffer (optional wenns ein byte[] ist auch Offset und Count) und teilt somit mit, wieviel max. gelesen werden soll. Als Rückgabewert kommen die Anzahl der gelesenen Bytes. Mehr ist es nicht -- das macht das Konzept vom Stream so universal einsetzbar (sowas finde ich ganz einfach super).

Ob der tatsächliche Stream ein FileStream, NetworkStream, etc. ist spielt dabei keine Rolle. Für die Verwendung vom Stream braucht man auch nicht* wissen wie NetworkStream unter der Haube funktioniert, da in .NET das Liskovsches Substitutionsprinzip befolgt wird.

* es schadet aber nicht 😉

gibt es schon fertig bei nuget

Kann sein. Aber bei "trivial Aufgaben" ist der Aufwand bei NuGet oft höhere, da* Suchen ob es etwas gibt

  • wenns mehrere gibt evaluieren was am besten passt
  • mind. ReadMe lesen / Doku lesen

Zusätzlich hier noch das Thema im Forum -- in dieser Zeit wäre die Lösung inkl. Tests wohl schon fertig 😉

mfG Gü

19.07.2022 - 14:36 Uhr

Hallo RedByte, willkommen im Forum!

Bitte nur konstruktive Rückmeldungen

Konstruktive Rückmeldungen beginnen schon mit der Frage und wie einfach es potentiellen Helfern gemacht wird.
Dazu zähle ich "hab ein Problem, Code ist auf PasteBin, schau ihn dir an" nicht unbedingt. [Hinweis] Wie poste ich richtig?
Wo hängst du genau? Hast du mit dem Debugger schon versucht den Programmablauf zu verfolgen?
Lässt sich das Problem durch ein einfacheres ersetzen (z.B. nur 2x2 Felder) und funktioniert dort der Algorithmus?

mfG Gü

19.07.2022 - 13:49 Uhr

Hallo sandreas,

ganz verstehe ich das Problem nicht bzw. warum soviel drumherum diskutiert wird.
Schreib einen Stream-Wrapper, dessen Ctor Offset und Länge auch übergeben wird, und das Problem ist gelöst.

Per Definition der Stream.Read-APIs wird maximal count Bytes gelesen, d.h. es kann weniger sein. Falls nichts mehr zu lesen ist, so wird 0 zurückgegeben.
Damit lässt sich das Problem fast trivial lösen.

mfG Gü

19.07.2022 - 13:43 Uhr

Hallo Bronstein,

was mich wunder -- bei der Fehlermeldung -- warum Out-Of-Process steht, da ist nirgends konfiguriert (od. ist das der Standard, weiß ich nicht).
In der Projektdatei (csproj) und der web.config sollten die HostingModels ident sein.

D.h. entweder


<!-- csproj --> 
<PropertyGroup>
    <AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
</PropertyGroup>

<!-- web.config -->
<aspNetCore processPath ="dotnet"
            arguments   =".\test.dll"
            hostingModel="outofprocess">
<!-- ... ->

oder


<!-- csproj --> 
<PropertyGroup>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>

<!-- web.config -->
<aspNetCore processPath ="dotnet"
            arguments   =".\test.dll"
            hostingModel="inprocess">
<!-- ... ->

Probier dies einmal explizit zu setzen und schau dir die Fehlermeldung -- die hoffentlich nicht mehr kommt 😉 -- genau an.

mfG Gü

18.07.2022 - 12:25 Uhr

Hallo Bronstein,

hast du auch das Hosting Bundle (x86) installiert?
Sehe das nicht im Screenshot. Ohne dem, wegen ASP.NET Core Module v2, kann der IIS nicht mit ASP.NET Core kommunizieren.

mfG Gü

16.07.2022 - 09:43 Uhr

Hallo Bronstein,

Da ich eine 32Bit DLL verwende habe ich im IIS Application Pool 32bit auf true gesetzt
...> Fehlermeldung:
HTTP Error 502.5 - ANCM Out-Of-Process Startup Failure

Das ASP.NET Core Hosting Bundle, in dem das ASP.NET Core Module (ANCM) enthalten ist, muss auch als 32bit-Variante vorhanden / installiert werden.

Ich tippe mal dass du die 64bit-Variante installiert hast, denn darauf deuten die Fehlermeldungen hin.

mfG Gü

11.07.2022 - 11:43 Uhr

Hallo Palladin007,

in einer streng typisierten Programmiersprache gibt es keinen Grund NRTs nicht zu verwenden.

NRTs sind Teil vom Typsystem (während der Entwurfszeit) bzw. eine Erweiterung / Ergänzung dessen.
Etwas überspitzt: diese nicht zu verwenden wäre wie alle Argumente mit dynamic* antatt konkreter Typen zu schreiben. Oder eine untypisierte zu verwenden...

Wer also Typsicherheit haben will, sollte auch NRTs verwenden. Am besten mit <TreatWarningsAsErrors>true</TreatWarningsAsErrors> in den Projekteigenschaften.

* Laufzeitverhalten außer Acht gelassen, denn dynamic ist langsam

So betrachtet ist es besser, dass es in eine NullReferenceException rennt, sofort auffällt und dann auch leicht(er) zu finden ist, als ein Logik-Fehler.

Hier liegt mMn bei vielen ein Verständnisfehler vor.
NRT sind eine Annotation, die zur Entwurfszeit via Compiler eine Hilfe gibt.
Das Laufzeitverhalten wird dadurch nicht beeinflusst. D.h. zur Laufzeit sind (bei öffentlichen / public APIs) daher sehr wohl Null-Prüfungen durchzuführen.
Siehe z.B. auch eine Diskussion im dotnet-docs Repo (und die Kommentare darunter) dazu.

Der große Vorteil von NRTs ist, dass der Compiler durch statische Analyse prüfen kann ob null zulässig ist od. nicht.

Da eben public APIs dennoch auf Null geprüft werden sollen, findet der große Vorteil bei internen APIs Anwendung. "Intern" ist hier nicht nur auf die internal, private, etc. (also alles außer public) begrenzt, sondern kann auch eine public-Methode sein, die nur innerhalb einer Anwendung / einer Organisation verwendet wird.
Anders gesagt: wenn nicht public im Sinne von "Verwendung für alle" sein soll, so können die Null-Checks auch entfallen falls die statische Prüfung vom Compiler ausreicht -- ergänzt (natürlich) mit Unit-Tests.

Auch public APIs profitieren von NRTs, da so via Methoden-Signatur ersichtlich ist ob null erlaubt ist od. ob bei (falscher) Übergabe von null eine NRE (besser: ArgumentNullException von der Validierung) geschmissen wird. D.h.


public int Foo(object? obj)
{
    // null kann für obj übergeben werden, die Implementierung hier muss damit umgehen können

    return obj is null 
        ? 0
        : obj.GetHashCode();
}

public int Bar(object obj)
{
    // null ist nicht gestattet, daher sollte das Argument validiert werden
    ArgumentNullException.ThrowIfNull(obj);

    return obj.GetHashCode();
}

internal int Baz(object obj)
{
    // null ist nicht gestatt, es ist ein kein öffentliches API, daher reicht eine Debug-Prüfung aus
    Debug.Assert(obj is not null);

    return obj.GetHashCode();
}

Auch sind die weiteren Annotation wie [NotNullWhen], etc. sehr hilfreich v.a. im Zusammenhang mit Try-Patterns, da so der Compiler im Zuge des "control flows" weiß wann der Wert null ist od. nicht.
Das hilft einfach Fehler zu vermeiden. Und zwar nicht erst bei Tests od. noch später, sondern während des Schreibens vom Code. Und es ist hinlänglich bekannt, je früher ein Fehler erkannt / behoben wird, desto weniger Kosten wurden dadurch verursacht.

Man sollte einfach pauschal immer davon ausgehen, dass es null sein kann und entsprechend darauf prüfen.

Ergänzend zu Abts Kommentar dazu, dem ich zustimme, noch folgendes Analogon: bei Werttypen kann auch einfach default verwendet werden, aber prüft jemand ob der Wert default ist od. nicht?
Ja, der Vergleich hinkt und es gibt auch Nullable-ValueTypes, aber der Kern der Aussage ist: durch Annotationen und Asserts lassen sich zur Entwurfszeit viele Fehler vermeiden ohne dass zur Laufzeit alles geprüft werden muss / braucht. Unit-Tests erledigen den Rest.

Wenn ein Entwickler vom Compiler darauf hingewiesen wird, auf null zu prüfen, dann setzt der ggf. ein sinnloses Default-Verhalten (oder Werte) um, die dann erst irgendwann später als Logik-Fehler auffallen.

Dann liegt das Problem aber zwischen Bildschirm und Bürostuhl 😉

... die dann erst irgendwann später als Logik-Fehler auffallen.

Das sollte doch bei Unit-Tests schon auffallen. Spätestens bei Integrations-Tests müsste das bemerkt werken -- idealerweise durch CI.
Wobei der Compiler nicht darauf hinweist "auf null zu prüfen", sondern der Compiler weist darauf hin, dass der Wert unerlaubterweise null ist.

NullReferenceExceptions sind immer Entwicklungsfehler.

👍 -- auch wenn "fail early" gut ist, sind NREs einfach Bugs die durch Tests detektiert werden sollten bevor ein Produkt veröffentlicht wird.

mfG Gü

05.07.2022 - 20:04 Uhr

Hallo Fabiano,

wie Palladin007 angemerkt hat geht das via MsBuild-Conditions, z.B.


<ItemGroup>
    <ProjectReference Condition="'$(Configuration)' == 'Debug'" ...

    <!-- od. Release statt Debug -->
    <PackageReference Condition='$(Configuration)' != 'Debug'" ...
</ItemGroup>

VS kann damit umgehen. Aber i.d.R. gibt es dafür keinen Grund, denn wie Abt erwähnte gibt es dazu Symbolpakete bzw. in die Assembly eingebette Symbole, so dass das Debug-Verhalten besser funktioniert.

Daher sollte bei Fragen idealerweise auch das eigentliche Ziel mit angegeben werden, damit potentielle Helfer wissen worum es geht.
Es kann ja sein, dass sich der Fragende in eine Sackgasse begiebt, das aber aufgrund der sehr konkreten Frage nicht sofort ersichtlich ist -- sich aber erahnen lässt.

mfG Gü

02.07.2022 - 08:36 Uhr

Hallo Kriz,

vllt. ist eine "einfache SQL Datenbank", also eine relationale Datenbank, hier nicht die beste Wahl. Mach dich mit dem Konzept von Graph-Datenbanken vertraut. Mit denen können solche Beziehungen besser abgebildet werden.

mfG Gü

30.06.2022 - 09:03 Uhr

Hallo Loofsy,

System.Text.Json

Wie nutzt du das? Direkt od. indirekt via ASP.NET Core WebAPI*, etc.?
In den Serialisierungs-Optionen (Blick in die Doku) kann das Verhalten von Anführungszeichen eingestellt werden.

* statt Client/Server selbst zu erstellen ist es fast immer vorzuziehen ein dafür entwickeltes Framework zu verwenden um sich auf den Anwendungscode statt auf die Infrastruktur konzentrieren zu können

mfG Gü

28.06.2022 - 17:41 Uhr

Hallo CPlusPlusSharp,

KISS -> sofern möglich nimm "generic math", denn das wurde genau dafür geschaffen.
Ab .NET 7 (kommt im Herbst) ist es dabei, für .NET 6 ist es "experimental" aber verfügbar.

Sonst mach das Konstrukt auch recht einfach -- v.a. wenn du es intern nutzen willst, also kein NuGet-Paket daraus machen willst. Z.B.


internal static Vector<T> MySuperVectorMethod<T>(Vector<T> vector)
{
    if (typeof(T) != typeof(int) || typeof(T) != typeof(double) ...)
    {
        throw new NotSupportedExcepted("Pech gehat, geht nur int, double, ...");
    }

    // Hier passt es dann
}

Der JIT wendet hier auch "dead code elimination", d.h. das if wird zur Laufzeit entfernt und effizienter Code generiert.

PS: hab das Thema nicht mehr ganz verfolgt, daher hoffe ich jetzt nicht am Thema vorbei geschrieben zu haben.

mfG Gü

28.06.2022 - 14:21 Uhr

Hallo sandreas,

Und allgemein? Magst du das Projekt? Neutral oder eher "so wird das nie was"? 🙂

Ja ich mag das Projekt*. Schaut sehr sauber aus, auf GH-ReadMe (prüf dort mal das Encoding, sind ein paar Spezial-Zeichen dabei) sind alle nötigen Infos vorhanden so dass sich damit arbeiten lässt bzw. sofort ein Überblick gegeben ist.
Code hab ich nur überflogen, der passt soweit**. Bei den Tests noch ein paar mehr Fälle testen (v.a. Randfälle / edge-cases wie keine Tags vorhanden beim Parser, etc.).

* auch wenn ich mangels Bedarf es selbst wohl eher nicht verwenden werde, aber da du es hier so nett vorgestellt hast, hab ich es mir angeschaut 😉
** die Anmerkungen oben sind davon unberührt, das kann ja noch geändert werden und Optimierungsmöglichkeiten finden sich fast überall...

mfG Gü

28.06.2022 - 12:41 Uhr

Hallo backspeck42,

Wenn allerdings hier im Forum nur sehr konkrete fragen gewünscht sind

Das ist nicht der Fall. Es kann auch allgemein sein.
Nur sollte das fairerweise auch so deklariert werden -- die Leute hier helfen gerne und freiwillig (in ihrer Arbeitszeits od. Freizeit), das sollte man nicht überstrapazieren.

Aber genug damit, lass uns beim Thema bleiben.

mfG Gü

28.06.2022 - 11:45 Uhr

Hallo backspeck42,

MessagePack hab ich angesehen - da bräuchte ich halt auch eine Surrogate-Klasse, da ich sonst die Attribute nicht einfügen kann. Oder kann MessagePack auch ISerializable nutzen und ich habe etwas übersehen?

Bei der Recherche nicht nur beim 1. gefundenen bleiben 😉
Es gibt ein paar Libs für .NET dazu.
Ziehe da auch die Möglichkeit von batch-basiertem Serialisieren in Betracht, sonst passiert wiederum alles im RAM auf einmal.

sondern eher Anregungen, Vorschläge was in welchem Falle besser ist und was zu bedenken wäre, Vor- und Nachteile - die habe ich nun auch bekommen. Daher "wehrte" ich mich dagegen, meinen Code zu posten

  • das hättest du schon zu Beginn schreiben können (dann hätte ich weniger schreiben können)
  • für den nächsten konkreten Fall gibt es vermutlich wieder andere Möglichkeiten die besser geeignet sind -- daher wozu die allgemeine Abhandlung?

mfG Gü

28.06.2022 - 10:42 Uhr

Hallo backspeck42,

ich kann "Newtonsoft.BSON" und "BinaryFormatter" schon gar nicht mehr lesen -- das steht in jedem deiner Beiträge 😉

Hilf dir selbst und geh doch bitte auf die Fragen, welche die gestellt werden ein. Auch das würde schon öfters nahegelegt.
Seit Gestern ist als neue Info eigentlich nur "komplexe Typen, Problem auch mit List<int> zeigbar" hinzugekommen. Dafür ist dieser Thread schon recht lange geworden.

Da ich eine List<int> nicht als komplex bezeichnen würde, werden die konrkreten Typen wohl anders ausschauen, nur wie?
Danach richtet sich doch gerade die Serialisierung. Gibts Zyklen, sind die Typen immer gleich, etc. sind da Fragen zu denen du die Antwort liefern solltest bevor jemand danach fragen muss -- schließlich willst ja auch du die Hilfe haben.

"Ein Bild sagt mehr als tausend Worte" ist so ein Spruch der Berechtigung hat. Übertragen auf ein Forum mit Thema Programmierung: "Ein Code sagt mehr als tausend Worte" 🙂
(wobei mit Code hier nur der relevante Teil ohne Infrastruktur-Rauschen gemeint ist)

Es soll in einen Stream serialisiert werden und später daraus gelesen. Soll nun der Stream von Beginn an gelesen werden (als IEnumerable<T> als Rückgabe) od. eher "random access" im Stream?

Protobuf wurde schon erwähnt, aber das wurde wegem dem Schema (proto-files) eher abgelehnt. Wenn die (komplexen) Typen doch recht einfach sind, so ist die proto-File ebenfalls recht einfach.
Hast du an andere Formate wie MessagePack gedacht bzw. diese evaluiert?

Es wäre auch möglich die Daten per BinaryWriter in durch einen Zip-Stream (o.ä.) zu jagen, aber MessagePack, Protobuf sind hier i.d.R. überlegen, da sie speziell für solche Szenarien konzipiert wurden.

Nur zur Verdeutlichung / Beispiel: binäres Speichern eines int benötigt 4 byte (per Definition in C# / .NET). Protobuf hat hier eine Optimierung indem bei Werten aus dem Intervall [sbyte.MinValue, sbyte.MaxValue] nur das LSB gespeichert wird, also nur 1 byte benötigt wird. Für [short.MinValue, short.MaxValue], etc. analog.
Klar lässt sich das auch selbst so umsetzen, aber wenn es eine millionenfach genutze Komponente gibt, so ziehe ich diese vor, da mehr Entwicklung dorthin geflossen ist als ich selbst erreichen könnte. Von allfälligen Bugs und deren Fixes ganz zu schweigen.

mfG Gü

28.06.2022 - 10:16 Uhr

Hallo sandreas,

auch wenns eine (single file) EXE als Ausgabe gibt und es per-se keine Klassenbibliothek ist, so würde ich interne Typen als internal markieren, da dies Implementierungsdetails sind. Der Vorteil davon ist, dass diese nach belieben geändert werden können ohne das "public api" zu verletzen und entsprechend SemVer eine neue Hauptversionsnummer erfordern würde.

Sind die Implementierungsdetails internal so könnten ein paar Optimierungen bzgl. Effizienz (CPU und Speicher / GC) durchgeführt werden.

Weiters würde ich das Projekt aufteilen, so dass für den Benutzer* die EXE (wie bisher) zur Verfügung steht

  • es eine DLL (NuGet) zur Verwendung als API (in eigenen Projekten, Web, etc.) gibt

wobei die EXE selbst ein Konsument der DLL ist -- sozusagen als einfacher Wrapper / Driver um die DLL angereichert mit den Commands die im Projekt verfügbar sind.

mfG Gü

27.06.2022 - 19:32 Uhr

Hallo backspeck42,

beschreib noch ein paar der Anforderungen, wie* nur für Verwendung in deinen Anwendungen od. allgemeine Verwendbarkeit

  • schnell serialisieren od. möglichst wenig Speicherbedarf
  • welche Typen (Werttypen, Klassen, Listen, Vererbung) sollen serialisiert werden
  • gibt es ein Schema für die Typen od. eher schemalos
  • etc.

Anhand solcher Kriterien lassen sich dann Technologien wählen bzw. Vorschläge unterbreiten.

mfG Gü

26.06.2022 - 18:21 Uhr

Hallo CPlusPlusSharp,

"Generic Math" ist ein neues Feature von .NET -- wird mit .NET 7 kommen und könnte etwas sein wonach du suchst.

mfG Gü

07.06.2022 - 11:59 Uhr

Hallo,

persönlicher Nachtrag:
Ich hab keine primäre Motivation Code zu schreiben, der extra Ressourcen-schonend ist und so z.B. auch für weniger CO2-Emissionen sorgt.
Jedoch finde ich es gut, wenn im Hinterkopf / Unterbewusstsein ein paar Gedanken in dieser Richtung vorhanden sind. Dadurch wird dieses Ziel irgendwie auch unbewusst verfolgt.

mfG Gü

07.06.2022 - 11:51 Uhr

Hallo Abt,

Code sollte v.a. les- und wartbar (sowie testbar) geschrieben werden. Dabei sollen und dürfen natürlich Konstrukte verwendet werden, welche dieses Ziel unterstützen.
Da sind wir uns sicher einig.

Nachhaltiger Code, im Sinne von Vermeidung unnötiger Ressourcen, wird (glücklicherweise) immer bedeutender*. Daher wollen wir auch ein wenig über den Standardhorizont hinausblicken und ein wenig Bewusstsein dafür schärfen. Ich nehme an daher gibt es auch https://github.com/BenjaminAbt/SustainableCode.

Trimming ist momentan eine Nische. Mit ein Grund dafür ist wohl auch, dass viele Teile vom .NET Framework noch nicht ganz trimm-freundlich sind** -- das wird sich mit .NET 7 und späteren Versionen bessern. Weiters dass wohl auch etliche Anwendungen framework-dependent laufen, daher Trimming untergeordnet ist.

Genauso ist (native) AOT (ahead of time compilation -- im Gegensatz zu JIT (just in time compilation)) noch eher eine Nische und in den Startlöchern.
Bisher war die Tool-Unterstützung dafür auch eher mangelhaft, aber das bessert sich gerade.

AOT und Trimming gehen Hand-in-Hand und sollten im Idealfall nativen Code für die gewählte Plattform produzieren, so dass* keine Assemblies in IL-Code -- od. wie bei R2R (ready to run) mit IL-Code und Maschinencode -- vorliegen, sondern eben direkt ausführbarer Maschinencode

  • kein JIT nötig ist, da der Code schon zur Build-Zeit komplett übersetzt wurde
  • in den "binaries" nur jene Code-Teile vorhanden sind, die tatsächlich benötigt werden
  • Code kann besser optimiert werden (eher für zukünftige .NET Versionen geplant)

Nachteilig bei AOT ist, dass der alte .NET-Grundsatz (der eigentlich erst durch .NET Core galt) "compile once, run everywhere" nicht mehr gilt, da bei der Kompilierung die Zielplattform bekannt sein muss.

Aber dadurch ergeben sich ein paar Vorteile bzgl. Ressourcen, nämlich* wesentlich kleiner Binaries

  • benögiten weniger Speicherplatz -- ist für viele kein Kriterium, aber in Hinsicht Blazor / Webassembly nicht unkritisch

  • das OS muss weniger Daten in den RAM laden --> weniger RAM-Belastung und auch schneller

  • kein JIT nötig --> zusammen mit den weniger Daten die zu laden sind, (viel) schnellerer Start der Anwendung -- bei lang laufenden Diensten nicht so wichtig, dafür aber bei Apps die oft gestartet werden (serverless, Container-Lösungen, ...)

Je nach Ziel-Plattform (klassischer Server, Cloud / Serverless, Mobil, etc.) sind die Einsparungen mehr od. weniger eklatant und relevant.
SustainableCode (Link siehe oben) beschreibt hier ein wenig mehr warum (für alle die das noch nciht gesehen haben).

In .NET beginnt die Reise mit AOT erst. Daher sollten wir auch jetzt schon einen Blick darauf werden und frühzeitig bestimmte Dinge berücksichtigen, dann ist es später einfacher.
Das soll jetzt aber keinesfalls eine Aufforderung sein, Linq durch manuell geschriebene Schleifen zu ersetzen. Es soll Linq dort verwendet machen, wo es sinnvoll ist. Jetzt und in Zukunft.

Aber es sollte nicht die Abhängigkeit zu Linq ins Projekt gebracht werden, nur um Enumerable.Empty<T> verwendet zu können.
Falls Linq ohnehin verwendet wird, so kein Problem. Anderfalls ist das in Hinsicht AOT hinderlich.
Da wäre ev. Array.Empty<T> passender, da diese im ausgeführten .NET Code-Pfad mit hoher Wahrscheinlichkeit sowieso dabei ist. (Klar, geht es dabei auch wieder darum, wie es verwendet wird (siehe Benchmarks oben, sofern korrekt) um nicht durch die Verwendung in der App mehr CPU-Ressourcen zu benötigen als vorher eingespart wurden.

.NET geht Dev-freundlich den Weg von Globalen Usings; Linq ist Teil davon.

Solange Linq nicht tatsächlich verwendet wird, so erstellt der Kompiler auch keine Referenz zu Linq in der Assembly. Das zählt.
Das gilt für alle Paketreferenzen allgemein: falls kein Typ einer Referenz verwendet wird, so ist in der Assembly diese Referenz nicht vorhanden.
Somit haben global Usings keinen negativen Effekt diesebezüglich.

den es dann nur wegen des künstlichen Falls gibt.

Beim "künstlichen Fall" kann ich jetzt nicht folgen.
Dass mit Linq und v.a. durch dessen generische Art, jede Menge Instanzen erstellt werden ist real und nicht künstlich 😉 (falls das gemeint sei)

* auch wenn sich wesentlich mehr Ressourcen-Einsparungspotential durch Vermeidung von Video-Streaming, Gaming, Social-Media, etc. ergibt, zählt doch jeder kleine Beitrag ein bischen...

** Z.B. ist Reflektion und Code-Erzeugung zur Laufzeit trimmer-unfreundlich, jedoch basieren etliche Konzepte in .NET darauf, z.B. ASP.NET Core Dependency Injection.
Durch die Einführung der Roslyn Sourcegenerators, konnte schon viel reflektion-basiertes umgeschrieben werden. Aber bei weitem noch nicht alles, das dauert halt.

mfG Gü

07.06.2022 - 10:01 Uhr

Hallo,

es gibt noch einen Punkt der bei Enumerable.Empty<T> beachtet werden soll bzw. in Zukunft noch wichtiger erscheinen wird.

Nämlich dass es sich dabei um eine Linq-Methode handelt, d.h. es wird Linq ins Projekt hineingeholt und das erzeugt einen größeren "Fussabdruck" der Anwendung in Hinsicht auf Ressourcen-Verbrauch.

In Zukunft wird v.a. das Thema IL-Trimming immer bedeutender, daher ist Linq hier eher ein Antagonist und wird / sollte womöglich vermieden werden, falls statischer Fussabdruck der App ein Kriterium ist.
Dies geht i.d.R. auch einher mit Startzeit der App (wichtig v.a. bei serverless Umgebungen, etc.).

Array.Empty<T> ist direkt in System.Private.CoreLib, daher ist es nicht so gewichtig wie Linq, hat aber auch seinen Fussabdruck, da es generisch ist und kann so u.U. ein paar Instanziierungen haben (1 für alle Referenztypen und eine je Werttyp).

Das soll jetzt nicht heißen, dass Linq per se vermieden werden soll, denn es is ja durchwegs sehr praktisch um kurzen leserlichen Code zu schreiben, aber es sollte auch nicht außer Acht gelassen werden, was es bedeutet solche Typen und Konstrukte zu verwenden.

mfG Gü

03.06.2022 - 16:38 Uhr

Hallo,

Also in Zukunft lieber Enumerable.Empty nutzen - tut nicht weh und ist schneller.

"Initialisierung" mit null ist am schnellsten und effizientesten.

Je nach folgender Verwendung kann die Initialisierung per Sentinel wie Array.Empty<T> od. Enumerable.Empty<T> sinnvoll sein, da so der null-Check entfällt.
Allerdings kann auch für eine leere Menge (wie sie Array.Empty und Enumerable.Emtpy bereit stellen) bei Verwendung z.B. in foreach od. anderen Linq-Methoden teil beträchtlicher Overhead ausgeführt werden nur um letztlich festzustellen, dass es eine leere Menge ist. Da kann ein null-Check effizienter sein.

Es kommt jedoch sehr darauf an was man will (und wie die Benchmarks dafür gestaltet werden).

Bei


List<int> list = ?
int sum = Sum(list);

static int Sum(List<int>? list);

hängst es von der Implementierung von Sum ab, wie list initialisiert wird.

Am effizientesten hier ist wohl:


List<int>? list = null;

static int? Sum(List<int>? list)
{
    if (list is null) return null;

    // Summe bilden
}

, da der null-Check sehr effizient ist (im Maschinencode nur ein test rdx, rdx) und entweder keine Schleife für die Summe od. kein Iterator für die Summe erstellt / ausgeführt werden muss.
Dies geht allerdings nur, wenn wie hier der Rückgabewert geändert werden kann bzw. die "Sentinel-Prüfung" verschoben wird.
Hier konkret wird int? zurückgegeben, d.h. es müsste an anderer Stelle geprüft werden ob HasValue true ist.

Was ich damit v.a. ausdrücken will: die zitierte Aussage ist pauschal falsch -- es kommt vielmehr auf den konkreten Fall darauf an.

Zurück zum ganz ursprünglichen Problem vom OT:

  
public class TestClass  
{  
  public string Name { get; set; }  
  
  public IEnumerable<string> Lines { get; set; } = new List<string>();  
}  
  

hier würde ich einfach


public class TestClass
{
	public string Name { get; set; }

	public IEnumerable<string> Lines { get; set; }
}

verwenden.
Es schreibt ja auch niemand


public class TestClass
{
	public string Name { get; set; } = "Dummy Name der dann eh ersetzt wird, aber nur damit es halt nicht null ist --> Sentinel";

	public IEnumerable<string> Lines { get; set; } = Array.Empty<string>();
}

(gut vllt. etwas realer mit string.Empty).

Der Time-Punch beim Array kommt (wahrscheinlich) durch das Cast von Array auf IEnumerable zustande.

Im Benchmark-Code finde ich Consumer und Consume nicht, daher keine Ahnung warum.

mfG Gü

24.05.2022 - 09:51 Uhr

Hallo Palladin007,

danke fürs Update.
Ja schauen wir einmal was / wie es wird. Das solte dann, nicht nur wegen der rechtilchen Bedenken, wohl auch vertraglich sauber geregelt werden, damit alle auf der sicheren Seite sind.

mfG Gü

18.05.2022 - 16:48 Uhr

Hallo,

jetzt zeigt sich warume es wichtig mit möglichst genauen Begriffen zu arbeiten 😉

Das heisst das vorhandene Zertifikat (mit CERTIFICATE und PRIVATE KEY Abschnitt) kann ich als Client-Zertifikat nehmen

"Client-Zertifikat" ist hier undeutlich und je nach dem was genau gemeint ist hat ClaraSoft recht od. auch nicht.

In Bezug auf SSL (lässt sich vom Thema ableiten) hat ClaraSoft recht.
Der Server braucht den public und private key damit er "verschlüsseln" kann. Der Client hingegen braucht vom Server nur den public key.
TCPListener ist server-seitig, daher klappte es vermutlich nicht, da kein private key vorhanden ist.

Ist bei "Client-Zertifikat" jedoch der Zusammenhang "Authentifizierung per Client-Zertifikat" (da auch mit SSL / TLS zusammenhängt) so benötigt der Client public + private key, aber seine eigenen! Und nicht jene vom Server.

Grundsätzlich sollten die private Schlüssel (keys) nur auf der Seite bleiben zu der sie gehören -- daher auch "private".
D.h. Client private key kennt der Server nicht und umgekehrt. Alles andere ist absolut unsicher (und fahrlässig).

mfG Gü

17.05.2022 - 16:39 Uhr

Hallo Kriz,

bei X509Certificate2.CreateFromCertFile muss hierfür ein Zertifikat mit privatem Schlüssel angegeben werden. Oder der private Schlüssel wird als extra Argument bei dieser Methode angegeben.

Für die Serverseite sind public und private key nötig, andernfalls kann SSL nicht funktionieren.

mfG Gü

13.05.2022 - 14:04 Uhr

Hallo Palladin007,

GC.Collect bitte nur als Notlösung betrachten, da dies die interne Arbeit und Tuning vom GC durcheinander bringt.

PerfView ist mächtig, aber nicht trivial und intuitiv.
Wenn du willst und es gestattet ist, so kann ich mir die Dumps einmal anschauen und dann eine grobe Art Anleitung dazu erstellen.
Aber ich muss bei PerfView auch immer wieder "reinkommen", da ich es recht schnell wieder vergesse 😉

mfG Gü

PS: aber erst am Montag, übers WE bin ich nicht da.