Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von gfoidl
Thema: Namensliste in csv-Datei Vornamen alphabetisch sortieren
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo shutouke,

Zitat
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ü

Thema: Hashcode von Strings
Am im Forum: Grundlagen von C#

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ü

Thema: Ich habe noch immer mit den .NET Core Nachfolgern Probleme
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Hallo theuserbl,

Zitat
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.
Zitat
- 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.
Zitat
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ü

Thema: Ich habe noch immer mit den .NET Core Nachfolgern Probleme
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Hallo,

Zitat
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!
Zitat
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
Zitat
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.
Zitat
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ü

Thema: Min() zweier Gleitkommazahlen zurückgeben
Am im Forum: Grundlagen von C#

Hallo Sw4t,

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

mfG Gü

Thema: StreamWrapper zum Limitieren der Position und Length
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

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ü

Thema: StreamWrapper zum Limitieren der Position und Length
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo sandreas,

Zitat
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 ;-)

Zitat
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ü

Thema: Backtracking Knight Problem
Am im Forum: Rund um die Programmierung

Hallo RedByte, willkommen im Forum!

Zitat
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ü

Thema: StreamWrapper zum Limitieren der Position und Length
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

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ü

Thema: C# Projekt unter IIS zum Laufen bringen
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

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ü

Thema: C# Projekt unter IIS zum Laufen bringen
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

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ü

Thema: C# Projekt unter IIS zum Laufen bringen
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Hallo Bronstein,

Zitat
Da ich eine 32Bit DLL verwende habe ich im IIS Application Pool 32bit auf true gesetzt
...
Fehler
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ü

Thema: C# 8 Nullable reference types - Pro & Con
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

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

Zitat
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.
Zitat
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.
Zitat
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 ;-)
Zitat
... 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.
Zitat von Abt
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ü

Thema: Debug-Projektreferenz und Release-Nuget-Package
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

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ü

Thema: Architektur einer Lebenssimulation
Am im Forum: Rund um die Programmierung

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ü

Thema: Datenübertragung mit JSON
Am im Forum: Netzwerktechnologien

Hallo Loofsy,

Zitat
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ü

Thema: Generics Typparameter geeignet einschränken?
Am im Forum: Grundlagen von C#

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ü

Thema: Projektvorstellung: tone - cross plattform audio tagger für die Kommandozeile
Am im Forum: Projekte

Hallo sandreas,

Zitat
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ü

Thema: Serialisierung großer Datenmengen (Binär)
Am im Forum: Rund um die Programmierung

Hallo backspeck42,

Zitat
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ü

Thema: Serialisierung großer Datenmengen (Binär)
Am im Forum: Rund um die Programmierung

Hallo backspeck42,

Zitat
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.
Zitat
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ü

Thema: Serialisierung großer Datenmengen (Binär)
Am im Forum: Rund um die Programmierung

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ü

Thema: Projektvorstellung: tone - cross plattform audio tagger für die Kommandozeile
Am im Forum: Projekte

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ü

Thema: Serialisierung großer Datenmengen (Binär)
Am im Forum: Rund um die Programmierung

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ü

Thema: Generics Typparameter geeignet einschränken?
Am im Forum: Grundlagen von C#

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ü

Thema: Enumerable.Empty<T> oder Array.Empty<T>
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

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ü

Thema: Enumerable.Empty<T> oder Array.Empty<T>
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

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.
Zitat von Abt
.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.
Zitat von Abt
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ü

Thema: Enumerable.Empty<T> oder Array.Empty<T>
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

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ü

Thema: Enumerable.Empty<T> oder Array.Empty<T>
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Hallo,

Zitat
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:
Zitat


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).
Zitat
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ü

Thema: MemoryLeak "behebt" sich selbst durch Memory-Snapshot
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

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ü

Thema: Fehler The server mode SSL must use a certificate with the associated private key bei SslStream.AuthenticateAsServer
Am im Forum: Web-Technologien

Hallo,

jetzt zeigt sich warume es wichtig mit möglichst genauen Begriffen zu arbeiten ;-)

Zitat
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ü