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

17.01.2019 - 16:01 Uhr

Hallo Kriz,

hier im Forum haben wir dazu Forumssuche nach kantenerkennung. Sonst auch nach "edge detection" suchen.

Wenn es kein Cloud-Dienst sein soll, so würde ich mich bei AForge umschauen.

mfG Gü

13.01.2019 - 15:19 Uhr

Hallo T-Virus,

Entsprechend macht es Sinn alle drei Abläufe durch einen Task verarbeiten zu lassen.

du hast sicher "je einen Task" gemeint?
Wenn das dann korrekt umgesetzt wird, so sind wir bei Abts Antwort.

mfG Gü

13.01.2019 - 15:06 Uhr

Hallo vitafit,

das Problem beginnt damit, dass für das/dass der Kontext der Wörter betrachtet werden muss, somit wäre ein Parsen zu einem "Syntaxbaum" nötig und anhand dessen lassen sich Regeln anwenden unter der Voraussetzung dass es solche Regeln (exakt) gibt.

mfG Gü

24.12.2018 - 09:50 Uhr

Hallo PaddelCore,

vllt. auch noch "Dispatcher", der basierend vom Kommando auf den entsprechenden Handler (= Methode) verteilt / dispatched.

mfG Gü

20.12.2018 - 09:08 Uhr

Hallo Limnfo,

da es mehrere Möglichkeiten zum Zeichnen gibt, wäre es auch gut zu wissen ob die 2D-Bilder eher eine Pixel- od. Vektorgrafik sind.

mfG Gü

12.12.2018 - 10:36 Uhr

Hallo C#Gustl,

ich hoffe dich richtig verstanden zu haben. Da würde nicht Lazy<T> verwenden, sondern Task<T>.

Also die Tasks erstellen, in die Liste packen und dann beim Iterieren kannst du sie awaiten.

mfG Gü

11.12.2018 - 11:00 Uhr

Hallo sugar76,

gibt es allerdings auch einen Mehraufwand bei der Implementierung.

Es hat halt alles Vor- und Nachteile. Kurzfristig mag es Mehraufwand sein, aber langfristig (mag) es sicher eine vorteilhafte Lösung sein.

Nicht klar ist mir, wie das Konzept UnitOfWork bzw. DbContext...

In Abts Demo-Projekt im Bereich InMemoryQueryHandlers gehört das angesiedelt. Er hat dort IAuthorsRepository injiziert (per Dependency Injection), du würdest hier den DbContext injizieren.

mfG Gü

10.12.2018 - 13:44 Uhr

Hallo sugar76,

ich bin für Variante 1, denn der DbContext ist schon eine UoW, daher braucht das nicht neu / doppelt implementiert werden.

wiederverwendbare Queries im Repository implementieren kann.

Wenn du den CodeFirst-Ansatz bei EF (Core) verwendest, so kannst du die DbContext-Klasse auch erweitern und dort diese Queries einbauen.
Bei DB-First kannst du die partielle Klasse erweitern.

Allerdings koppelst du dich damit an EF (Core). Wenn das kein Nachteil ist, so passt dieser Weg. Willst du keine Kopplung an EF (Core) haben, so wäre Variante 2 od. eine andere Abstraktion besser.

mfG Gü

10.12.2018 - 09:59 Uhr

Hallo sugar76,

Die Alternative ist ja, ein UnitOfWork zu verwenden:
...
ist dieses Verfahren auch in einer Desktop-Anwendung zu empfehlen?

Ja.
Genau für solche Zwecke gibt es die UoW auch.

Was, wenn der Benutzer zwischen Schritt 2) und 3) einen Kaffee trinken geht?

Wenn nicht jemand anders an den gleichen Daten in der Zwischenzeit etwas ändert, so passiert nichts anderes als wenn der Benutzer keinen Kaffee trinken ginge.
Hat jemand anders in dieser Zeit an den gleichen Daten etwas geändert, so kommt beim Update von der DB eine ConcurrencyException und diese kann entsprechend behandelt werden. Z.B. können die neuen Daten von der DB geladen werden um den lokalen Context aufzufrischen und dann mit den lokalen Änderungen erneut füttern -> geht es dann, gut, sonst dem Benutzer eine Mitteilung anzeigen.

mfG Gü

07.12.2018 - 11:38 Uhr

Hallo Abt,

StackOverflow-Exception zu vermeiden hilft

das in meinem Kommentar oben steht 😉

Der Weg via Stack<t> ist auch nicht immer ganz einfach und da kann der Code gleich richtig geändert werden.

Siehe dazu auch Forumssuche nach hanoi

mfG Gü

07.12.2018 - 11:17 Uhr

Hallo Seidenraupe,

Muss ich für ein Programm mit derartig vielen Iterationen etwas besonderes beachten?

Iterationen sind eher bei Schleifen angesiedelt, daher Iterationen nicht mit rekursiven Aufrufen verwechseln, denn es sind zwei Paar Schuhe.

Kommt der Garbage Collector nicht so schnell hinterher?

Bei einer StackOverFlowException mischt der Garbage Collector (GC) nicht mit, somit ist es unerheblich wie schnell er ist. Der GC ist für Daten auf dem Heap verantworlich, die von der managed Runtime alloziert werden.

Der Stack ist ein anderer Speicherbereich, bei dem es in der Natur eines Stapelspeichers nur Adress-Inkrementierung / -Dekrementierung gibt und somit kein GC nötig ist.

Für jeden Methodenauruf* werden Daten wie Rücksprungadresse, lokale Variablen, etc. auf den Stack gelegt und bei Rückkehr aus der aufgerufenen Methode wiederhergestellt. Das ist sehr effizient, aber bei vielen Methodenaufrufen, die nicht zurückkehren, kann der erlaubte Stapelspeicherbereich "überlaufen" und das äußert sich eben in einer StackOverFlowException.

* mit ein paar Ausnahmen, wie endrekursive Methodenaufrufe / inlineing außer Acht gelassen

Möglichkeiten zur Behebung / Umgehung sind somit:* iteratives Vorgehen verwenden -- wie von T-Virus vorgeschlagen

  • endrekurisves Verhalten (nicht immer leicht)
  • die Stapelspeichergröße erhöhen (ist hier aber eher ein Hack, als eine gute Lösung)

Hallo Abt,

ob Stack<T> passend ist, lässt sich nicht pauschal sagen, da der Algorithmus unbekannt ist.
Z.B. lässt sich


private static int SumRecursive(int n)
{
    if (n == 1) return 1;

    return n + SumRecursive(n - 1);
}

ohne Stack<T> in eine iterative Variante überführen:


private static int SumIterative(int n)
{
    int sum = 0;

    for (int i = 1; i <= n; ++i)
        sum += i;

    return sum;
}

mfG Gü

04.12.2018 - 20:18 Uhr

Hallo lutzeslife,

ja klar. Einfach den .NET Full Code nehmen und per Copy & Paste in ein "GitHub-Projekt" kopieren geht nicht so einfach, da spielen auch eine Menge (Schutz-) Rechte mit.*

Interessant wird wie sich z.B. der "Dinosaurier" Winforms weiterentwickeln wird, wenn er Einfüsse von der Open Source Community erhalten kann / wird.
Eigentlich aus MS-Sicht eine gute Sache, so können sie mit Hilfe der Community eine "eher tote"** Technologie weiterentwickeln, ohne selbst etliche Ressourcen dafür zur Verfügung zu stellen.

Ähnlich ist es z.B. mit der BCL auch die in https://github.com/dotnet/corefx ("This repo contains the .NET Core foundational libraries") lebt und als "Reference Source" vom .NET Full verfügbar ist. Genauso für die Runtime, etc.

* beim Reference Source für die BCL wurde kürzlich die Lizenz zu MIT geändert, damit Portierungen zu .NET Core einfacher werden

** bewusst so geschrieben und es gibt keinerlei offizielle Andeutungen dazu, dass Winform tot sei, genau das Gegenteil wurde durch das Open Source ja gemacht. Auch bewusst in " gesetzt

mfG Gü

04.12.2018 - 19:43 Uhr

Hallo zusammen,

vor ein paar Jahren noch unvorstellbar, jetzt aber Realität:

mfG Gü

27.11.2018 - 10:18 Uhr

Hallo emuuu,

zur eigentlichen Frage kann ich nichts beitragen, aber bei

hinterlege in meiner UserDB noch ein weiteres Feld "Pincode"

hast du dir sicher gedacht, dass "Pincode" wie ein Passwort behandelt wird und somit auch gesalzen usw. wird -> [FAQ] DB-Password/Kennwort/Connection-String sicher speichern

mfG Gü

22.11.2018 - 18:19 Uhr

Hallo Gimmick,

der Quellcode wird garkeinem Environment zugeordnet

Der Quellcode ist "neutral". Die Anpassung an die Environment passiert via Konfiguration.

dass der Masterbranch zum aktuellsten Deployment gehört, egal ob Dev, Test oder Prod?

Drück es umgehrt aus: aus dem Masterbranch wird ein Artefakt (Komponente, Anwendung, ...) erstellt und dieses Artefakt wird an die Environments wie Dev, Test und Prod weitergereicht (ohne dabei verändert zu werden, siehe Konfig).

mfG Gü

22.11.2018 - 11:21 Uhr

Hallo,

Die Dateien + Informationen darüber sollen irgendwo übersichtlich zur Verfügung stehen.

Das wäre eher etwas für ein Wiki (z.B. Confluence). Darauf können auch Stakeholder Zugriff haben (für bestimmte Bereiche).

mfG Gü

22.11.2018 - 11:11 Uhr

Hallo emuuu,

die älteren SDKs doch getrost runterschmeißen können oder?

Ja. Stichwort "side by side installation" für die .NET Core SDKs.

gibt es noch weitere Dependencies die mir einen Strich durch die Rechnung machen könnten?

Eigentlich nur wenn du irgendein Projekt mittels global.json auf eine SDK-Versoin fixiert hast, sonst fällt mir gerade nichts ein.

mfG Gü

Edit: PS: um 37 Sekunden zu langsam beim Antworten 😉

20.11.2018 - 22:16 Uhr

Hallo pinki,

Als Lösung zum Select-Problem gäbe es auch noch die
>
(siehe TaskEnumerableAwaiter).

Nein, bitte nicht -- das ist auch nur ein schön verpacktest Task.WhenAll und bringt somit nichts an Verbesserung.

Wenn schon so in der Art, dann eher wie es in Throttling -- Begrenzung der max. Anzahl an gleichzeitig ausgeführten asynchronen Vorgängen umgesetzt ist, da hier "async durchgezogen" wird, ohne dass irgendwo blockierend auf ein Ergebnis gewartet werden muss.

async ist "viral" und sollte nie mit einem blockierenden Warten* verbunden werden.

* die einzige Ausnahme ist die Main-Methode, die ab C# 7 asynchron geschrieben werden kann und dort der Compiler zu GetAwaiter().GetResult() umschreibt, somit blockiert, aber hier macht es auch Sinn...

mfG Gü

20.11.2018 - 12:00 Uhr

Hallo Demokrit,

nimm / erstell dir eine ordentliche Datenstruktur, zerlege es in einfache Methoden und dann geht es fast von alleine.

Schau mal (die Bezeichner hab ich mangels Kontext nicht besser wählen können, sollten aber schon sinnvoller sein):


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var parser = new Parser();

            Dictionary<DateTime, Value> result = parser.GetMergedItems("data.csv");
        }
    }

    public class Parser
    {
        public Dictionary<DateTime, Value> GetMergedItems(string fileName, bool hasHeader = false)
        {
            var mergedItems = new Dictionary<DateTime, Value>();
            IEnumerable<(DateTime, Value)> items = ParseLines(fileName, hasHeader);

            foreach ((DateTime Date, Value Value) item in items)
            {
                if (mergedItems.ContainsKey(item.Date))
                    mergedItems[item.Date] += item.Value;
                else
                    mergedItems.Add(item.Date, item.Value);
            }

            return mergedItems;
        }

        private static IEnumerable<(DateTime Date, Value Value)> ParseLines(string fileName, bool hasHeader)
        {
            using (StreamReader sr = File.OpenText(fileName))
            {
                if (hasHeader) sr.ReadLine();

                while (!sr.EndOfStream)
                {
                    string line   = sr.ReadLine();
                    string[] cols = line.Split(';');

                    yield return ParseValue(cols);
                }
            }
        }

        private static (DateTime, Value) ParseValue(string[] cols)
        {
            if (!DateTime.TryParse(cols[0], out DateTime dt))
                throw new Exception(".....");

            Action<string, Action<int>> action = (s, setter) =>
            {
                if (!int.TryParse(s, out int tmp))
                    throw new Exception("...");

                setter(tmp);
            };

            Value value = default;
            action(cols[1], i => value.A = i);
            action(cols[2], i => value.B = i);
            action(cols[3], i => value.C = i);
            action(cols[4], i => value.D = i);
            action(cols[5], i => value.E = i);

            return (dt, value);
        }
    }

    [DebuggerDisplay("{A} | {B} | {C} | {D} | {E}")]
    public struct Value
    {
        public int A { get; set; }
        public int B { get; set; }
        public int C { get; set; }
        public int D { get; set; }
        public int E { get; set; }

        public static Value operator +(Value a, Value b)
        {
            return new Value
            {
                A = a.A + b.A,
                B = a.B + b.B,
                C = a.C + b.C,
                D = a.D + b.D,
                E = a.E + b.E
            };
        }
    }
}

Anmerkung: hier geht es explizit um das Addieren von Zeilen / Einträgen mit dem gleichen Datum, daher wurde das Addieren auch direkt einkodiert. Um das generischer zu erledigen, wäre ein "Aggregator" passender und wie hier im konkreten Fall dann ein "SumAggregator" o.ä.
Auf diese Weise kann die Addition einfach gegen z.B. Mittelwert ausgetauscht werden, ohne dass der eigentliche Code verändert werden muss. Das würde dann so ausschauen:


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            var parser     = new Parser();
            var aggregator = new SumAggregator();

            Dictionary<DateTime, Value> result = parser.GetMergedItems("data.csv", aggregator);
        }
    }

    public class Parser
    {
        public Dictionary<DateTime, Value> GetMergedItems(string fileName, IAggregator aggregator, bool hasHeader = false)
        {
            var mergedItems = new Dictionary<DateTime, Value>();
            IEnumerable<(DateTime, Value)> items = ParseLines(fileName, hasHeader);

            foreach ((DateTime Date, Value Value) item in items)
            {
                if (mergedItems.TryGetValue(item.Date, out Value value))
                    mergedItems[item.Date] = aggregator.Operate(item.Value, value);
                else
                    mergedItems.Add(item.Date, item.Value);
            }

            return mergedItems;
        }

        private static IEnumerable<(DateTime Date, Value Value)> ParseLines(string fileName, bool hasHeader)
        {
            using (StreamReader sr = File.OpenText(fileName))
            {
                if (hasHeader) sr.ReadLine();

                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();
                    string[] cols = line.Split(';');

                    yield return ParseValue(cols);
                }
            }
        }

        private static (DateTime, Value) ParseValue(string[] cols)
        {
            if (!DateTime.TryParse(cols[0], out DateTime dt))
                throw new Exception(".....");

            Action<string, Action<int>> action = (s, setter) =>
            {
                if (!int.TryParse(s, out int tmp))
                    throw new Exception("...");

                setter(tmp);
            };

            Value value = default;
            action(cols[1], i => value.A = i);
            action(cols[2], i => value.B = i);
            action(cols[3], i => value.C = i);
            action(cols[4], i => value.D = i);
            action(cols[5], i => value.E = i);

            return (dt, value);
        }
    }

    public interface IAggregator
    {
        Value Operate(Value a, Value b);
    }

    public class SumAggregator : IAggregator
    {
        public Value Operate(Value a, Value b) => new Value
        {
            A = a.A + b.A,
            B = a.B + b.B,
            C = a.C + b.C,
            D = a.D + b.D,
            E = a.E + b.E
        };
    }

    [DebuggerDisplay("{A} | {B} | {C} | {D} | {E}")]
    public struct Value
    {
        public int A { get; set; }
        public int B { get; set; }
        public int C { get; set; }
        public int D { get; set; }
        public int E { get; set; }
    }
}

Und dann wäre es noch schön wenn das weitergetriebe wird und Unit-Tests erstellt werden, so dass das korrekte Funktionieren der Klassen / Methoden geprüft werden kann.

mfG Gü

20.11.2018 - 11:16 Uhr

Hallo mipa_acc,

die folgende sarkastische Aussage kann ich mir leider nicht verkneifen, aber der Wunsch nach aktuellen Technologien und WebForms widerspricht sich schon sehr 😉

.NET Core bedeutet nicht zwangsweise ein Arbeiten und Linux. .NET Core bietet die Möglichkeit auch unter Linux u.a. lauffähig zu sein. Ob es genutzt wird ist eine andere Sache.

Ich würde ASP.NET Core basierend auf .NET Core verwenden (serverseitig), dann bist du mit den aktuellen Technologien dabei.

Clientseitig kannst du in Angular, React oder Vue? schauen.

Sollte man RazorPages verwenden, bzw. in wie fern bringt mir das Vorteile?

Ein Vorteil ist dass keine extra Controller mit der passenden Action explizit erstellt werden muss.
Wenn du also serverseitig nur simples HTML zurückliefern willst (Layout + Page gerendert durch Razor) und der Rest passiert am Client, indem er via WebAPI vom Server die Daten lädt, so ist das ganz praktisch. Siehe auch Introduction to Razor Pages in ASP.NET Core

mfG Gü

19.11.2018 - 22:56 Uhr

Hallo Papst,

mir gefällt Variante 2 am besten...außer die Details zur Kategorie sind eher statisch / ändern sich nicht zu oft und die Wahrscheinlichkeit dass die eingehenden Ids einen Großteil aller möglichen Kategorien abdecken und diese Daten auch hinreichtend oft benötigt werden, so gefällt mir auch Variante 1 besser, v.a. wenn diese zusammen mit einem Cache (z.B. Redis) kombiniert wird 😉 Klar?

mfG Gü

19.11.2018 - 22:08 Uhr

Hallo Papst,

Vorschläge mit der .Result Property...oder mittels GetAwaiter().GetResult() ?

Beides synchronisiert u.U. blockierend und sollte vermieden werden bzw. wäre es dann einfach gleich das synchrone Api aufzurufen.

Aktuell hängt da ein DB Call (ggf. mit Cache) dahinter, perspektivisch soll da ein HTTP Call zu einer API hinterhängen.

In dem skizzierten Fall würde für jedes Item eine asynchrone Operation ausgeführt werden. Das kann eine ganze Menge werden ("chatty") und ist eher suboptimal. Besser wäre wenn das Ganze "chunky" passiert, d.h. für alle / möglichst viele Items eine asynchrone Operation und dann das Ergebnis zu verarbeiten.
Das wäre so in der Art wie dein letzer Vorschlag.

Ausblick: mit C# 8 werden asynchrone Stream / Iteratoren möglich und ich gehe davon aus, dass es in der Folge auch eine Art "async Linq" geben wird.

mfG Gü

17.11.2018 - 10:58 Uhr

Hallo Flo,

die Lösung wurde dir ja genannt, aber zum Hintergrund warum es so ist: vermutlich wurden die Bindingredirects* nicht korrekt generiert. Durch das Verwenden der NuGet-Pakete ist das hinfällig, da beide Seiten die gleiche Version verwenden. Hier hat dann wohl das Tooling irgendwie die Versionen nicht ausfinding machen können und daher keine Redirects generiert.

Schau dir dazu auch* Issues with .NET Standard 2.0 with .NET Framework & NuGet · Issue #481 · dotnet/standard

an.

* mMn ist dieses "Feature" ehere eine Notlösung, denn "hübsch" ist das alles nicht

mfG Gü

15.11.2018 - 10:45 Uhr

Hallo zusammen,

mit HTML 5 wurden Web Worker eingeführt.
Praktisch angewandt hab ich diese Möglichkeit noch nicht. Sei es da ich keinen Anwendungsfall für sinnvoll gehalten habe, einfach nicht daran dachte dass es möglich wäre, od. sonst irgendwas.

Daher interessiert mich ob und für welche Szenarien Web Worker tatsächlich eingesetzt werden (können).

Es gibt zwar Aufzählungen über Einsatzmöglichkeiten, wie John Resig - Computing with JavaScript Web Workers, aber die erscheinen mir eher akademischer Natur.

mfG Gü

14.11.2018 - 19:37 Uhr

Hallo Ichthys,

etwas Ressourcen spart

Ressourcen in Bezug auf Speicherbedarf u.U.
Ein int ist 4 bytes, während ein short 2 bytes ist. Das wäre somit die Hälfte, wenn da nicht Data structure alignment ins Spiel kommen würde.

Wie von FZelle erwähnt macht es eigentlich nur Sinn wenn ein Marshalling zu unmanaged / native Code nötig ist. Dort ist dann bei structs auch ein entsprechendes Layout vorzugeben (Sequential od. Explicit), damit die Runtime (CLR) kein Padding einbaut so wie ihr es passt.

Ressourcen in Bezug auf Rechenleistung eher gegenteilig.
Ein x64 Prozessor hat eine Wortbreite von 64 bit, also von 8 bytes (z.B. long) und mit den Registern rax, rbx, ...r15 kann direkt damit gearbeitet werden.
Für 4 byte Daten (int) hat der Prozessor einen gesonderten Modus (eax, ebx, ...), bei dem er nur die "halbe Registerbreite" verwendet und dieser Modus wird auch vom (Ryu)JIT unterstützt in der Codegenerierung.
Kleiner Datentypen wie short können vom Prozessor zwar verwendet werden (ax, ...) nur der (Ryu)JIT hat das nicht in seiner Codegeneriung und "weitet" die Werte (durch "zero extension" movzx) auf int od. long auf um damit rechnen zu können. Das ist weniger performant als mit den "nativen" Datentypen zu rechnen. (Anmerkung: daher gibt es in C++ auch den Datentyp size_t, welcher der Wortbreite des Prozessors bzw. exakter der Platform entspricht. Für C# gibt es eine Bestrebung auch so einen Datentyp zu haben, da sich damit v.a. low-level Library-Code wie er in einigen BCL-Typen vorhanden (z.B. Span, etc.) effizienter gestalten lässt, z.B. ist auf x64 ein for-Schleife die eien Array durchläuft mit long als Zählvariable effizienter als mit int, da für den Arrayzugriff (= Pointer) keine int -> long Erweiterung nötig ist).

Manche Prozessoren haben auch Durchsatzeinbußen wenn die "Viertelregister" (ax, ...) verwendet werden.
Bei x86 verhält es sich ähnlich, aber bei dem kenn ich mich nicht (mehr) gut aus.

Das war jetzt ein wenig low-level.

mfG Gü

12.11.2018 - 16:38 Uhr

Hallo Abt und HeikoAdams,

ich hab den Verdacht ihr redet (schreibt) aneinander vorbei. HeikoAdams' Begriff sind hier zwar nicht die treffensten, aber ich lese schon heraus dass er verteht worum es geht.

Das Testlabor für .NET findet sich in https://github.com/dotnet/corefxlab
Dort werden neue "Dinge" ausprobiert und zu einer bestimmten Reife gebracht. Sollte es sich dort als nützlich herausstellen, so wird es nach https://github.com/dotnet/corefx übertragen und zur "Serienreife" weiter entwickelt. corefx ist somit kein Labor und keine Spielwiese 😉
Aber Features können hier rascher umgesetzt werden als es bei .NET Full der Fall ist -- siehe oben. Ist ein Feature jedoch nützlich, so kann es auch nach .NET Full portiert werden -- wie hier der Ablauf genau ist, bleibt wohl eher intern bei MS.

mfG Gü

12.11.2018 - 16:27 Uhr

Hallo T-Virus,

ich denke du hast dich da in etwas verrannt bzw. falsch aufgefasst.
LinQ arbeitet wie ein Fließband und nach dem Pull-Prinzip, d.h. der jeweilige Verbraucher holt sich die nächsten Daten und dabei wird nur soweit iteriert wie nötig. LinQ arbeitet daher grundsäztlich nach O(n), wobei auch nur einmal über die gesamte Quelle iteriert wird -- wie schon angemerkt worden ist.

Grob schaut es dabei immer so aus:


public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> filter)
{
    foreach (T item in source)
        if (filter(item))
            yield return item;
}

Im Quellcode (entweder der Reference-Source od. jener in corefx auf GitHub) schaut es ein wenig anders aus, da sämtliche Optimierungen und Spezialisierungen (wie wenn IEnumerable<T> ein Array ist, etc.) angewandt worden sind. Genauso wird im Quellcode oft auf yield return verzichtet und stattdessen der Iterator selbst programmiert (yield return wird vom C#-Compiler in den entsprechenden Iterator umgeschrieben).

mfG Gü

08.11.2018 - 10:05 Uhr

Hallo,

provokant sagen, das .NET Core die Spielwiese ist

Ich verstehe HeikoAdams, aber damit keine Missverständnisse auftreten zur Klarstellung:
*.NET Core wird nach https://semver.org/ versioniert und Installationen sind side-by-side. *.NET Full hat irgendeine MS-Versionierung, aber die Installation (der gleichen Haupt-Versionsnummer) is in-place, d.h. eine neue Version überschreibt die Alte. Hier kann MS sich nicht erlauben Inkompatibilitäten einzubauen. Es wäre fatal wenn eine Anwendung die unter .NET 4.7.1 fehlerfrei lief unter .NET 4.7.2 Bugs hat. Bei .NET Core kann der Entwickler explizit gegen eine Version testen und so die "Freigabe" dafür erteilen, zumindest lässt sich das Testen.

Hinzu kommt dass bei MS die Ressourcen -- zumindest sagen sie das so -- gar nicht so groß sind, um .NET Core und .NET Core die gleiche Liebe zukommen zu lassen und der Fokus liegt klar auf Ersterem.

Mit der "Spielwiese" hat HeikoAdams aber insofern recht, dass .NET Core als Open-Source-Projekt entwickelt wird und somit via Issues / PR die Community ungleich mehr Mitwirken an der "Gestalt" der APIs, vom Framework, etc. hat.
Während bei .NET Full der Weg via Connect / UserVote eher mühsam und langatmig war.

Anmerkung: der Schritt .NET Core als OS-Projekt zu erstellen war großartig.

mfG Gü

07.11.2018 - 11:51 Uhr

Hallo p!lle,

😁

in den letzten C#-Versionen hat sich bei den "Collection Initializern" auch etwas geändert, z.B. dass


var numbers = new Dictionary<int, string> {   
    [7] = "seven",   
    [9] = "nine",   
    [13] = "thirteen"   
};

(Quelle)
möglich ist.

Der generierte Code ist dabei ganz interessant (ILSpy, etc. -- entweder direkt das IL anschauen od. eine alte C#-Version einstellen, so dass gesehen werden kann was hinter den Kulissen generiert wird). So lassen sich dann auch Einsatzmöglichkeiten / potentielle Fehler besser ausloten.

mfG Gü

07.11.2018 - 11:45 Uhr

Hallo,

Durch Span<T> kommt eine Menge Arbeit auf das .NET Framework zu. Span<T> ist über das NuGet-Paket System.Memory auch für .NET Full verfügbar. Allerdings in der Implementierungs-Variante "Slow Span", d.h. ohne direkte Runtime-Unterstützung (JIT + GC) wie es bei .NET Core ("Fast Span") der Fall. Also funktionieren tut es, nur nicht so performant wie bei "Fast Span". Die fehlenden JIT + GC Teile werden durch eine etwas andere Implementierung "emuliert".

UTF-8 Strings, mit der nun mal die ganze Übertragung im Web läuft und damit das ständige Casten in .NET wegfällt.

Nicht nur das Casten, sondern v.a. das Allozieren von Speicher fällt weg. Generell vereinfach sich das typische Parsen von utf-8 -> parser -> string (allocate + utf-16) -> logic -> writer -> utf-8 zu utf-8 parser (uses memory pool) -> logic -> writer -> utf-8 writer. Es fallen somit auch die Konvertierungen zwischen UTF-8 und der String-Repräsentation in UTF-16 vom Framework weg. Das spart natürlich eine Menge Zeit und Arbeit für den GC.

Wenn Span<T> ins .NET Framework kommt, wird darauf wohl auch ASP.NET Core laufen werden.

Es geht ja nicht nur um Span<T> (siehe oben), sondern auch um sonst jede Menge APIs, die sich in .NET Core schneller umsetzen lassen als in .NET Full, da bei .NET Full die (in-place) Kompatibilität ein wichtiges Ziel ist.

mfG Gü

07.11.2018 - 11:33 Uhr

Hallo,

muss man immer durch ein Double-Teilen, wenn man keine Rundungsfehler haben will. Bei Int geht logischerweise immer was verloren.

Gerade bei double gibt es Rundungsfehler*, während int exakt ist.

Nur bei int wird Ganzahldivision angewandt und für diese Aufgabe ist diese nicht das gewünscht, daher ist Abts Hinweis, dass mit double gerechnet werden soll korrekt.

* bedingt durch die Natur der Sache, spezifiziert in IEEE 754

mfG Gü

06.11.2018 - 10:35 Uhr

Hallo p!lle,

diese Möglichkeit gab es schon seit Einführung der "object initializer" (C# 3).
Der Ctor von FirstClass erzeugt SecondClass und im Objekt-Initialisierer wird dann nur mehr die Eigenschaft MyString vom bereits instanziierten Typ SecondClass gesetzt. Genauso wie du selbst geschrieben hast. Ohne Ctor, der SecondClass erzeugt, gibt es eben die NRE.

mfG Gü

02.11.2018 - 10:49 Uhr

Hallo filmee24,

ein Ereignis / Event ist "nur" ein Delegate und somit kannst du alle Methoden verwenden, welche der Delegat-Typ bietet.

Die Antwort ist genauso allgemein gehalten wie deine Frage 😉
Wie schaut denn das Ereignis aus, um gezieltere Antworten geben zu können.

mfG Gü

30.10.2018 - 10:49 Uhr

Hallo HeikoAdams,

warum zitierst du nicht den ganzen Teil? 😉

A better performing and more reliable debugger, moving to an out-of-process 64-bit process.

Hervorhebung von mir.

mfG Gü

30.10.2018 - 10:48 Uhr

Hallo,

mit ASP.NET Core 3.0 gibt es einen neuen Versuch: Discussion: ASP.NET Core 3.0 will only run on .NET Core

Ich sehe das als logischen Schritt und vermeidet im Framework-Code von ASP.NET Core auch etliche Klimmzüge um .NET Full unterstützen zu können.

mfG Gü

26.10.2018 - 18:21 Uhr

Hallo trib,

in Member Order Returned by GetFields, GetMethods … findest du die Hintergrundinfo dazu. Kurz: es geht darum wie das Reflektion-System die Daten intern cached.

mfG Gü

25.10.2018 - 19:24 Uhr

Hallo Konux,

bei Abhängigkeit:

Dabei hat die Klasse Schreiner aber die Klasse Hammer nicht als Attribut angelegt.

Ich würde "nicht unbedingt als Attribut" schreiben. Schreiner kann sehr wohl ein Attribute (Eigenschaft) Hammer haben. So wie es formuliert ist, würde die Eigenschaft verboten sein.

bei Multipizitäten bei Assoziationen:
DI ist passend, aber die Beschränkung auf Konstrukor-Injektion od. Setter-Injektion ist nicht nötig. Mit beiden Varianten der DI lassen sich die Multipizitäten umsetzen.
Die Multipizitäten lassen sich aber auch via Methoden erstellen, also ohne Verwendung von DI.

1..10 das ist das Beispiel und die Beschreibung nicht (zusammen-) passend.
Beide Seiten der Assoziation müssen / können separat betrachtet werden und somit sollten auf beiden Seiten die Multiplizitäten angegeben werden, wenn sich die Beschreibung darauf bezieht.

Sind die Code-Beispiele Java? Nur zur Erinnerung: hier handelt es sich um ein C#-Forum 😉

Auf die paar Typos bin ich nicht eingegangen.

mfG Gü

25.10.2018 - 19:04 Uhr

Hallo filmee24,

noch als Ergänzung:

TaskCompletionSource ne Exception wirft, sobald einmal der Result gesetzt wurde.

Das ist auch gut so, denn die TCS lässt sich nur einmal verwenden. Sie ist eben ein Produzent für einen Task, der zugleich auch dessen Endstatus steuert (Completed, Exception, ...).
Könnte mit einer TCS mehrere Tasks "gesteuert" werden, so würde das die Tür für jede Menge Bugs, bedingt durch Race conditions, öffnen. Daher wurde dieses Verhalten unterbunden.

mfG Gü

14.10.2018 - 19:07 Uhr

Hallo Manfred77,

vorneweg: schau dir bitte [Hinweis] Wie poste ich richtig? an und beachte das auch. Genauso ist im Titel ein "Bitte um Hilfe!!!" nicht nötig, denn in fast jedem Thread bittet jemand um Hilfe.

Ein paar Hinweise zum gezeigten Code:

  
int i = Convert.ToInt32(Console.ReadLine());  
  

Hier wäre statt Convert.ToInt32 die Verwendung von int.TryParse besser bzw. sicherer, da so auch Fehleingaben behandelt werden können, währen Convert.ToInt32 das Programm mit einem Fehler abstürzen lässt.

while (tausch == true)  

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

Ansonsten: was hast du denn in Bezug auf Quicksort schon probiert?
Falls du dir erhoffst, dass wir dir den Code dazu liefern, so ginge das nur via Jobbörse, denn das ist nicht der Sinn eines Forums (siehe eingangs erwähnten Link).

mfG Gü

13.10.2018 - 19:44 Uhr

Hallo filmee24,

die sauber Lösung hat Alf Ator genannt.

Sonst kannst du noch im Service die OnXXX-Methoden entsprechend überschreiben (und z.B. auch ins Eventlog einen adäquaten Eintrag schreiben, warum das Stoppen nicht durchgeführt wurde, etc.).

mfG Gü

12.10.2018 - 11:36 Uhr

Hallo sindibad,

wenn es das Problem rein in VS gibt, so vermute ich dass hier Intellisense et.al. den Verweis zur alten Version gecached hat und die Änderung nicht mitbekommt. Durch Löschen vom .vs Verzeichnis könnte somit der Cache geleert werden.
Das ist aber nur eine Vermutung von mir.

mfG Gü

09.10.2018 - 10:24 Uhr

Hallo sugar76,

wo bei diesem Vorgehen denn der Vorteil von Code-First gegenüber Database First liegt?

Es gibt immer Vor- und Nachteile 😉

Als Vorteile sehe ich bei diesem Vorgehen mit Code-First (ohne bestimmte Reihenfolge):* die Modell-Klassen können leicht in eigenes Projekt ausgelagert werden

  • die Modell-Klassen können leicht angepasst werden, falls mehr als nur POCOs nötig ist (ohne partielle Klassen, etc. verwenden zu müssen wie beim DB-first Ansatz)
  • in den Modell-Klassen können alle C# Sprachfeatures wie Vererbung (gemeinsame Basisklassen), etc. angewandt werden (bei DB-first nur umständlich möglich)
  • Verbindungszeichenfolge ist einfacher (da das edmx-Mapping entfällt) und somit kann sie universeller verwendet werden, bei DB-first ist sie sehr speziell für diesen einen Anwendungsfall
  • Code ist leichter versionierbar bzw. Änderungen sind leichter nachvollziehbar (Änderung an Klassen vs. Änderung am edmx (XML))

Nachteile:* Designer (edmx) gibt es nicht -- ob dies wirklich ein Nachteil ist, soll jeder für sich entscheiden. Die Modell-Klassen können auch sonst visualisiert werden bei Bedarf.

  • das Mapping ist teilweise schwerer zu coden als mit dem Designer von DB-first
  • benötigt oft mehr Entwicklungs-Zeit bis die Anwendung auf die DB zugreifen kann, aber langfristig ist es i.d.R. besser wartbarer

Diese List ist sicher nicht vollständig und auch geprägt von persönlichen Vorlieben / Erfahrungen und somti auch als solches zu betrachten, aber ich hoffe dass es als Orientierung hilfreich ist.

mfG Gü

07.10.2018 - 12:04 Uhr

Hallo sugar76,

ich vermute du hast ein kleines Verständnisproblem, denn auch mit Code-first kann gegen bestehende Datenbanken gemappt werden.

Database-first bezieht sich v.a. auf den EDMX-Editor, der so das Mapping von der bestehenden DB generiert (und angepasst werden kann).

Code-first erstellt das Mapping direkt duch Klassen, die entweder händisch erstellt werden od. per Reverse engineering aus einer bestehenden DB generiert werden können. Nota bene: auch die händisch erstellten Klassen können auf eine existierende DB mappen!

Persönlich hab ich die DB in einem SQL Server-Projekt in VS, das sich somit auch (per git) versionieren lässt. Der O/R-Code muss dann halt nachgezogen werden. Aber das ist mir lieber als die (automatischen) Migrationen (denen traue ich bei Live-Daten weniger als mir selbst 😉).

mfG Gü

05.10.2018 - 10:43 Uhr

Hallo sugar76,

Dann müsste man aber GetItems selbst als asynchron definieren oder?

Ja.

mfG Gü

03.10.2018 - 10:07 Uhr

Hallo sugar76,

kommt darauf an wie aufwändig GetItems ist. Ist es nur wenig aufwändig, so kannst du den Dispatcher dafür verwenden. Ist es jedoch aufwändiger -- z.B. dauert länger als 1s --, so würde ich die Arbeit lieber im ThreadPool erledigen lassen, da so der Dispatcher für UI-Aufgaben (rendern, ...) frei bleibt.

Wenn GetItems auf eine Datenbank od. einen WebService zugreift, so kannst du dort das async "durchziehen", dann wird der ThreadPool auch nicht wirklich belastet. Achte bei diesen Aufrufen aber dass ConfigureAwait(false) angegeben wird, denn hier ist es nicht nötig zurück in den UI-Thread zu delegieren. Das ist nur beim letzten await nötig, von dem aus es dann zur UI geht (wie in deinem Code).

mfG Gü

01.10.2018 - 10:28 Uhr

Hallo ErfinderDesRades,

im Kontext von WCF kannst du dafür auch Reflektion anwenden und so das Objekt erstellen.
Wenn die ConstructorInfo und PropertyInfo in einem Feld gecached wird, so ist es laufzeitmäßig nicht so schlimm und WCF verwendet intern auch jede Menge Reflektion, zumal letztlich die Daten mit (großer) Latenz übers Netzwerk geschickt werden.

Kannst du etwas mehr über den Kontext deines Problems berichten, denn so verstehe ich das Vorhaben nicht ganz und denke dass es alternative Wege dafür geben mag.

Übrigens "ObjectContext" ist nicht der richtige Datentyp-Name des 2.Objektes OperationContext?

mfG Gü

14.09.2018 - 16:01 Uhr

Hallo Abt,

Anweisungen selbst nichts (real genaues) über die Laufzeit aussagen;

Das stimmt, da eben nicht davon ausgegangen werden kann, dass nur ein Prozess exklusiv alle Ressourcen besitzt und auch die CPU ihrerseits Optimierungen durchführen kann. Dem widerspreche ich ja nicht.
Sondern "dass eine Schleife der größte potentielle Messfehler sei" und "der Code zur Laufzeit optimiert werde", denn das stimmt beides nicht.

Letzteres nicht, da der JIT bzw. die Runtime von .NET nicht so arbeitet.
Durch Tiered-JITing (s.o.) wird sich das ändern, aber das ist momentan Preview.

Ersterers stimmt nicht, da die Schleife trivial und keine weiteren unbekannten Abhängigkeiten hat, die nicht vorhersehbar und stationär sind. In x64 Maschinencode ist es nur:


L0000: xor eax, eax
L0002: xor edx, edx
L0004: inc eax
L0006: inc edx
L0008: cmp edx, 0x64
L000b: jl L0004

Die CPU führt immer die gleichen Befehle und Sprünge aus. Die beiden inc werden wohl durch das Pipelining "gleichzeitig" ausgeführt werden und der Branchpredictor wird den Sprung auch korrekt (zu 99%, hier da i < 100) vorhersagen.
Wenn nun multi-tasking vom OS außer Acht gelassen wird, genauso wie automatische Takterhöhung der CPU, so ergibt sich dafür die gleiche Laufzeit bei jedem Durchlauf*. Die CPU hat alle Befehle dekodiert, usw. und es gibt keine Speicherzugriffe, da alle Variablen in Register gehalten werden und somit keine weiteren Latenzen die unterschiedlich sein können.

* der Branchpredictor gehört da noch berücksichtigt, daher wäre es bei Benchmarks auch wichtig eine Warmup-Phase zu haben, damit eben alles bereit ist für Messungen die stationäre Statistiken liefern sollen

Unabhängig davon geht es dem OT ja darum den Overhead des asynchronen Aufrufs zu ermitteln bzw. zu vergleichen. Daher sollte in der async-Methode auch so wenig wie möglich Arbeit getätigt werden, damit eben Aufruf-Overhead >> Arbeit ist. Sonst würde eher nur die Arbeit gemessen werden und der Overhead -> 0.
Daher ist der Vorschlag mit

  
await Task.Run(async () => { await Task.Delay(200); });  
  

auch suboptimal, da der Overhead untergeht und das erklärt auch warum sich die Ergebnisse bei dir kaum mehr unterscheiden.
Außerdem ist ein Task.Delay, das auf einem Timer basiert, wohl eine größere Messunsicherheit als eine for-Schleife.

Randnotiz:

Eine Schleife ist durch das potentielle Risiko des unterschiedlichen Laufzeitverhaltens einfach kein geeignetes Werkzeug für eine zuverlässige Laufzeitmessung; vor allem nicht im Mikro-Bereich. https://benchmarkdotnet.org verwendet gerade Schleifen um Mikrobenchmarks zu ermöglichen. Genauso alle anderen Benchmark-Tools, die den Namen verdienen.

mfG Gü

14.09.2018 - 14:58 Uhr

Hallo Telefisch,

um konkret helfen zu können fehlt uns der Kontext. Also* wo hostest du die Anwendung?

  • was macht der Controller?
  • ...

Mit den gegeben Infos lässt sich nur raten...

mfG Gü

14.09.2018 - 12:08 Uhr

Hallo johnnycc,

Der erste Aufruf dauert immer länger. Z.B.:

.NET basiert aktuell auf einem JIT (just in time compiler), der den vom C#-Compiler generierten IL-Code erst zu ausführbaren Maschinencode übersetzen muss. Dieses Übersetzung IL -> Maschinencode basiert beim ersten Aufruf*.
D.h. die Methode foo muss vom JIT verarbeitet werden, genauso wie Task.Run, etc. Eben alles das bisher noch nicht geJITet wurde.

Weiters ist in .NET vieles auf "lazy-initialisation" getrimmt. D.h. -- ähnlich wie beim JITen -- dass beim ersten Zugriff die Ressourcen, die benötigt werden, bereitgestellt werden. Dies hat den Vorteil gegenüber "eager-initialisation", bei dem alle Ressourcen unmittelbar beim Start zur Verfügung gestellt werden, dass nur jenes bereitgestellt wird, das auch tatsächlich benötigt wird -- das sogenannte "you pay for what you play".
Hier ist es bei Task.Run, das dem TaskScheduler anweist den übergebenen Delegaten auszuführen, nicht anders. Kurz: die benötigte TPL-Infrastruktur wird beim ersten Aufruf bereitgestellt. Für die folgenden Aufrufe sind diese Schritte nicht mehr nötig.

Aus diesen Gründen sollten bei Messungen eine Warmlaufphase eingebaut werden, um diesen "Start-Overhead" zu eliminieren. Tools wie das zitierte ttps://benchmarkdotnet.org/ machen das genau so.

* mit .NET Core 2.2 wird ein Tiered-Jitting der Standard werden, d.h. der IL-Code wird ohne Optimierungen nach Maschinencode übersetzt und falls die Runtime bemerkt dass eine Methode "heiß" ist, so wird diese erneut kompiliert, aber mit vielen Optimierungen, und anschließend diese optimierte Version verwendet. Unterm Strich soll das schnellere Startzeiten der Anwendung bringen und im Betrieb bessere Laufzeiten, da eben besser optmierter Code verwendet werden kann. Der JIT muss bis dato immer die Balance zwischen Schnelligkeit der Kompilierung und Optimierung (zeitaufwändig) treffen.

Hallo weismat,

StopWatch ist auch nicht sauber für das Messen von Microbenchmarks.

Warum? https://benchmarkdotnet.org/ misst intern auch mit der Stopwatch.
Der Vorteil von BDN ist dass es mehrere Messungen durchführt (inkl. Warmup, etc.) und dann statistische Aussagen liefert, so dass Messfehler (Standardabweichung, ...) ins Ergebnis einfließen können.
Das lässt sich selbst auch umsetzen...nur wenn es das mit BDN schon gibt kann auch das fertige getestete Tool verwendet werden, zumals die Verwendung recht einfach ist.

Hallo Abt,

aber natürlich auch an der Schleife.
So eine Schleife ist so ziemlich der größte potentieller Messfehler solch einer Angelegenheit.
Es ist überhaupt nicht garantiert, dass die Schleife immer die gleiche Zeit benötigt; der Code wird schließlich zur Laufzeit optimiert.

Mag sein dass ich dich hier falsch verstanden habe, aber eine for-Schleife ist so ziemlich das exakteste in solch einer Angelegenheit 😉
Tiered JITing außer Acht gelassen: ist der Code, der die Schleife beinhaltet, einmal durch den JIT gelaufen, so bleibt dieser Maschinencode bis ans Ende des Prozesses auch gleich. Somit sind es immer die exakt gleichen Anweisungen die in der Schleife ausgeführt werden.
Mögliche Unsicherheiten für die Messungen kommen hier nur den CPU-Instructioncache ins Spiel, aber bei so einem kleinen Schleifenrumpf ist mit ziemlicher Sicherheit davon auszugehen, dass hier kein Cachemiss auftreten wird beim Rücksprung an den Schleifenbeginn.

mfG Gü

06.08.2018 - 16:52 Uhr

Hallo CrocodileDundee,

eine Browser-basierte Lösung ist da eher ungeeignet

Nein, ich sehe das als sehr gut passend an. Auf dem raspberry pi lässt du eine asp.net Core Anwendung laufen (dein Konfigurations-Tool).

Eine WPF-Anwendung müsste ohnehin mit dem rpi kommunizieren und würde das nur umständlicher machen.

mfG Gü