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 Palladin007
Thema: Methodennamen erst zur Laufzeit bekannt
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Nutze doch einfach die Überladung, bei der Du den Delegate-Typ mitgeben kannst.
Dann tut's einfaches Casten

Delegate.CreateDelegate Method (System)

Thema: WPF Fensterposition und Größe speichern
Am im Forum: GUI: WPF und XAML

Ich hab mir den Code nicht angeschaut (und deinen Code zeigst Du nicht), aber negative Werte können durchaus vorkommen.

Die Position X:0/Y:0 ist immer links oben vom Haupt-Monitor!
Wenn Du links daneben einen zweiten Monitor hast, dann hat der eine negative X-Position.
Und wenn darüber ein zweiter Monitor ist, dann hat der eine negative Y-Position.

Thema: WPF Fensterposition und Größe speichern
Am im Forum: GUI: WPF und XAML

Du kannst nur Position und Maße speichern.
Was willst Du da noch machen bzw. was funktioniert nicht?

Position und Maße zu ändern, funktioniert auch heute noch, habe ich vorhin erst gemacht.

Thema: Methodennamen erst zur Laufzeit bekannt
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Du kannst anhand eines Delegates auch eine Action<int> erzeugen - macht den Aufruf etwas lesbarer

Thema: Methodennamen erst zur Laufzeit bekannt
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Naja, wobei man am Ende ja trotzdem noch Reflection braucht, um die jeweiligen Implementierungen zu finden.
Oder man registriert sie alle einzeln im Code, aber das will pollito ja nicht - was ich auch nachvollziehen kann ^^

Thema: Methodennamen erst zur Laufzeit bekannt
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Also ich würde daraus einzelne Klassen machen, die dann alle ein bestimmtes Interface implementieren.
Typen suchen und instanziieren ist immer noch Reflection, aber einfacher, als Methoden suchen und aufrufen.

Thema: Methodennamen erst zur Laufzeit bekannt
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Du kannst nur den Reflection-Aufruf umgestalten, aber es bleibt immer noch Reflection.
Z.B. ist es meines Wissens nach performanter, wenn Du die Methode nicht einfach ausführst, sondern ein Delegate dafür erstellst.

Aber besser wäre natürlich, Du müsstest gar nicht auf Reflection zurückgreifen, damit sparst Du dir diese ganze Komplexität.

Thema: Async Task-Synchronisation
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Zitat von gfoidl
Da hast du recht, das passt und wegen der Synchronisierung gibt es da auch kein Race.
Gut zu wissen, dass ich da richtig gedacht habe ^^
Zitat von gfoidl
Gestern hab ich auch einen Versuch unternommen mit ValueTask (IValueTaskSource) ohne Channel. Wurde aber schnell sehr komplex, so dass das wieder verworfen wurde, da eben die Channel hier schon alles bietet was benötigt wird.
Klar, wenn die Channels sowas in der Art schon machen, dann nehme ich natürlich auch diese Lösung.
Darauf zielte meine Frage hier ja ab: Eine mehr oder weniger fertige Lösung finden, damit diese Komplexität eben nicht testen muss.

Zitat von gfoidl
Unabhängig davon frag ich mich schon ob es nicht ein passendes Konstrukt dafür schon gibt
Naja, für einen Thread kann man das selber Verhalten ja mit dem klassischen lock erreichen - zumindest in meinem Fall.
Nur für Async geht genau das nicht, mein Gedanke mit dem anderen Verhalten soll das gleiche Verhalten wie vom lock ermöglichen.
Warum es dafür noch nichts gibt, wundert mich aber auch, das Problem sollte es ja auch in anderen Projekten geben, async Synchronisierung ist ja kein neues Thema.

Aber wenn es das wirklich nicht gibt - wovon ich jetzt mal ausgehe, wenn Du und Abt nichts kennen und wir nichts finden - dann mache ich daraus ein kleines NuGet-Package.

Thema: Async Task-Synchronisation
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Zitat von gfoidl
Das spart die wiederholte Allokation der WeakReference und _count kann gleich auf 1 gesetzt werden.
Stimmt, danke

Zitat von gfoidl
Da ist ein (latenter) Bug. Wenn TryEnter mit einem anderen obj aufgerufen wird als bisher in der WeakReference gehalten so wird jedesmal eine neue TaskCompletionSource erstellt. Bereits von der TaskCompletionSource (TCS) erzeugte Tasks können so nie komplettiert werden und das ist Fehlverhalten.
Müsste das nicht durch das "??=" umgangen werden?
Die TCS wird nur dann erstellt, wenn es noch keine gibt, sodass am Ende alle auf den gleichen Task warten.
Oder ich übersehe etwas, denn die AsyncSemaphore-Implementierung von Stephen T nutzt ja auch eine Queue, ich dachte nur, dass ich die nicht brauche...

Thema: Async Task-Synchronisation
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Ok, damit hab ich nicht gerechnet
Ich brauche (neben der Arbeit) noch etwas Zeit, um mich da Mal ausführlich einzuarbeiten, besonders da ich die Channel bisher auch nur vom Namen kenne.
Gerade bei so einem schwierigen Thema übernehme ich ungern Code, ohne jede Zeile erklären zu können, teils aus Interesse, teils weil ich ihn warten muss ^^

Bis dahin erst einmal ein riesiges Dankeschön

Zitat von gfoidl
Releaser ist ein Werttype, kann also nicht null sein, daher ist diese Annotation umsonst.
Ich weiß ^^
Ich habe es aber bewusst rein geschrieben, um den Unterschied zum zweiten out-Parameter offensichtlich zu machen, also dass je nach Rückgabewert nur einer von beiden genutzt werden soll - und es tut ja auch nicht weh.
Die TryEnter-Methode ist auch erst zum Schluss entstanden, weil die Enter-Methode für meinen Geschmack zu groß wurde und sich an der Stelle gut aufsplitten ließ.
Ich hatte erst etwas ganz anderes vor, hab das dann aber für übertrieben befunden und bin zu der zwar etwas merkwürdigen, dafür aber einfachen out-Lösung gekommen.

Zitat von gfoidl
Hab die Klasse ReEntryLock genannt, keine Ahnung ob es bessere Bezeichnungen gibt -- Namensgebung ist ziemlich das schwerste
Oh ja
Vielleicht irgendetwas mit "Ticket"?
Die ganzen anderen Worte, die mir in den Sinn kommen, sind bereits irgendwie vergeben

Thema: Async Task-Synchronisation
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Zitat
erstell dir eine eigene Datenstrukture welche für die Synchronisation zuständig ist.
Also gibt's das noch nicht - das habe ich befürchtet.
Zitat
Bei der Variante mit den Channel<T> gibts die "Kapazitäten" vor und wenns 0 wird, so heißt es warten.
Das wäre ja das Verhalten vom Semaphore, was ich aber gerade nicht haben möchte - deshalb ist auch eine auf Semaphore aufbauende Implementierung keine Lösung für mich.
Ich brauche das umgekehrte Verhalten, sodass 0 quasi ein Freifahrtschein für alle ist und der erste, der "gewinnt", darf danach exklusiv arbeiten, bis es wieder auf 0 steht.

Die Channel schaue ich mir aber trotzdem Mal an, ich hab nur grob was dazu gelesen und bin noch nicht tiefer eingestiegen - könnte sich noch lohnen.


Was sagst Du denn zu meinem Versuch? Das verhält sich bisher ja so, wie ich es brauche, nur wäre mir eine fertige Lösung lieber, vor allem, weil sich da so leicht schwer zu entdeckende Fehler einschleichen.
Man sagt dir ja einiges an Erfahrung und Detail-Wissen nach, über etwas Feedback/Kritik würde ich mich daher freuen
Alternativ kann ich auch unter "Code-Reviews" eine neue Frage auf machen (oder einer von euch spaltet ab), wenn es keine mehr oder weniger passende vorhandene Lösung gibt, ist es da vielleicht besser aufgehoben.

Thema: Async Task-Synchronisation
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Nein, keine State Machine.
Die Flow-Beschreibung war nur ein Versuch, es halbwegs verständlich zu beschreiben, das ist bei so Themen ja immer etwas schwerer

Thema: eBay API Request
Am im Forum: Web-Technologien

Nutze den HttpClient, der ist in einigen Punkten einfacher.

Und den Body kannst Du doch einfach als String zusammen bauen?
Beim WebRequest geht das mit OpenRequestStream und in den Stream musst Du dann noch deine Daten schreiben. Vergiss aber nicht, ContentType und ContentLength zu setzen.

Oder Du greifst auf Refit zurück, das kann dir extrem viel Arbeit abnehmen.
Wenn Du noch mehr Requests für andere Endpunkte brauchst, würde ich definitiv auf Refit setzen.

Thema: Async Task-Synchronisation
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

'n Abend,

ich habe das leidige Thema lock in einem async Kontext - was nicht geht und mir ist auch klar, warum es nicht geht.
Meine Frage zielt eher darauf ab, wie man das umgehen könnte.

Für ein generelles lock (nur einer gleichzeitig) kann man ja ein AsyncSemaphore nehmen.
Allerdings scheitert das, wenn der selbe Task EnterAsync nochmal aufruft, bevor der Releaser disposed wurde, genau das kann/darf bei mir aber vorkommen.
Meine Überlegung ist daher, dass ein Objekt als Reservierungs-ID verwendet wird und nicht (wie bei lock/Monitor) als ID für die reservierte Ressource.

Ich versuche es Mal stichpunktartig zu beschreiben:

  • Enter mit Obj1 => darf weiter arbeiten.
  • Enter mit Obj1 => darf weiter arbeiten.
  • Enter mit Obj2 => muss warten.
  • Exit mit Obj1
  • Obj2 muss immer noch warten.
  • Exit mit Obj1
  • Obj2 darf weiter arbeiten.
  • Exit mit Obj2
  • Enter mit Obj3 => darf weiter arbeiten.
Und so weiter, wobei aber egal ist, aus welchem Thread oder Task das aufgerufen wird, es zählt nur, welches Objekt übergeben wurde.
Oder vielleicht wird es mit etwas Code klarer:


var taskCount = 5;
var counter = new CountdownEvent(taskCount);
var myLock = new AsyncLock();

for (int i = 0; i < taskCount; i++)
{
    var id = i;

    _ = Task.Run(async () =>
    {
        object obj = id;

        try
        {
            using (await myLock.EnterAsync(obj, default))
            {
                for (int i = 0; i < 3; i++)
                {
                    using (await myLock.EnterAsync(obj, default))
                    {
                        Thread.Sleep(10);
                        Console.Write(id);
                    }
                }

                Console.WriteLine();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            throw;
        }
        finally
        {
            counter.Signal();
        }
    });
}

counter.Wait();
Die Ausgabe soll sowas sein wie:

111
444
000
222
333
Gibt es dafür schon etwas?

Mein erster Entwurf, der mit dem TestCode auch läuft:


public class AsyncLock
{
    private readonly object _syncRoot = new();
    private TaskCompletionSource? _waiter;
    private WeakReference? _obj;
    private uint _count;

    public Task<Releaser> EnterAsync(object obj, CancellationToken cancellationToken = default)
        => EnterAsync(obj, Timeout.InfiniteTimeSpan, cancellationToken);

    public async Task<Releaser> EnterAsync(object obj, TimeSpan timeout, CancellationToken cancellationToken = default)
    {
        var startTimestamp = DateTime.Now;

        while (true)
        {
            if (TryEnter(obj, out var releaser, out var waitTask))
                return releaser;

            if (timeout > Timeout.InfiniteTimeSpan)
                timeout -= DateTime.Now - startTimestamp;

            await waitTask
                .WaitAsync(timeout, cancellationToken)
                .ConfigureAwait(false);
        }
    }

    private bool TryEnter(object obj, [MaybeNullWhen(false)] out Releaser release, [MaybeNullWhen(true)] out Task waitTask)
    {
        lock (_syncRoot)
        {
            if (ValidateAccess(obj))
            {
                if (_obj?.IsAlive == false)
                    _count = 0;

                _count++;
                _obj = new(obj);

                release = new(this, obj);
                waitTask = null;
                return true;
            }
            else
            {
                _waiter ??= new();

                release = default;
                waitTask = _waiter.Task;
                return false;
            }
        }
    }

    public void Exit(object obj)
    {
        lock (_syncRoot)
        {
            if (ValidateAccess(obj))
            {
                if (_count == 1)
                {
                    _count = 0;
                    _obj = null;

                    Interlocked.Exchange(ref _waiter, null)?.TrySetResult();
                }
                else
                    _count--;
            }
        }
    }

    private bool ValidateAccess(object obj)
    {
        return _obj is null or { IsAlive: false }
            || ReferenceEquals(_obj.Target, obj);

    }

    public readonly struct Releaser : IDisposable
    {
        private readonly AsyncLock _owner;
        private readonly object _obj;

        internal Releaser(AsyncLock owner, object obj)
        {
            ArgumentNullException.ThrowIfNull(owner, nameof(owner));
            ArgumentNullException.ThrowIfNull(obj, nameof(obj));

            _owner = owner;
            _obj = obj;
        }

        public void Dispose()
            => _owner?.Exit(_obj);
    }
}
Mir wäre eine bestehende und gut getestete Lösung lieber, aber wenn es die nicht gibt:
Seht Ihr da mögliche Probleme? Ich habe nicht viel Erfahrung auf dem Gebiet
Wie könnte man das Ding nennen? AsyncLock oder AsyncMonitor finde ich nicht passend, da es sich ja eigentlich sehr anders verhält, als lock bzw. Monitor.

Thema: Trigger in CodeBehind erzeugen
Am im Forum: GUI: WPF und XAML

Zitat von Th69
evtl. mit Hilfe von AttachedCommandBehavior V2 aka ACB o.ä.
Das gibt's auch von Microsoft:
https://github.com/Microsoft/XamlBehaviorsWpf

Thema: Visual Studio lokale Datenbank Daten werden nach jedem Insert gelöscht
Am im Forum: Datentechnologien

Zitat von S4ndwichmaker
weiß ich gerade leider nicht in welches "Unterforum" meine Frage passt ich hoffe es ist hier richtig.
Ich finde deine Wahl richtig.

Dein Code dagegen aber nicht ...

Ein paar generelle Kritikpunkte:
  • Halte bitte Namenskonventionen ein, z.B. "InsertEntry" anstatt "db_eintragen" oder "nameTextBox" anstatt "textBox1", oder "[Configurations]" anstatt "[Table]"
  • Nutze SQL-Parameter! Wo auch immer das manuelle Zusammenstückeln von SQL noch empfohlen wird - die sollte man steinigen.
  • Alles, was IDisposable (bei dir: SqlConnection und SqlCommand) implementiert, sollte in einem using-Block stehen.
  • Bist Du sicher, dass Du ohne Transaktion arbeiten willst?

Und dein Problem:
Ein simples INSERT löscht keine Daten, das Problem liegt also nicht im gezeigten Code.
Was passiert denn vorher? Wird die DB vielleicht immer überschrieben? Wird sie woanders gelöscht?
Irgendwas passiert vor dem Insert, dass deine Datenbank alle Daten verliert.

Z.B. hatte ich vor Ewigkeiten Mal bei jemanden den Fall gesehen, dass die DB-Datei (bei Sqlite) im Projekt lag und mit ins Zielverzeichnis kopiert wurde - wo sie natürlich immer und immer wieder überschrieben wurde.

By the way:
Mit dem Entity Framework nimmst Du dir den Großteil der Arbeit ab.

Thema: Radio Button als Gruppe abfragen
Am im Forum: Grundlagen von C#

Ich persönlich würde in dem Event-Handler die Radio-Buttons (ob alle oder nur die Relevanten) abfragen und die ausgewählten Radio-Buttons auf ein Enum mappen.
Damit kann man dann andere Methoden aufrufen oder den Zustand anpassen und man muss sich nicht mehr um die Radio-Buttons kümmern.

Mit MVVM und WPF (oder andere ähnliche Frameworks) wäre das natürlich um einiges einfacher, aber es wurde ja nicht mitgeteilt, um was es sich handelt.

Thema: Konsolenanwendung braucht mehr als *.exe Datei
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Zitat von T-Virus
Der Hinweis mit der Auswahl ging mir darum, dass je nachdem was er ausgewählt hat auch noch das Framework beim Endanwender benötigt.
Aber ist natürlich richtig, sollte man nur noch nehmen wenn nötig uns sonst aust .NET 5+ setzen!
Das war auch nicht als Kritik an dich gemeint
Es sollte mehr ein Hinweis sein, da Viele lieber den augenscheinlich einfacheren Weg gehen (weil "kenn ich ja"), sich dabei aber nur noch mehr Probleme aufhalsen.

Thema: Konsolenanwendung braucht mehr als *.exe Datei
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Heute gibt's .NET 5 mit quasi neu entwickelter Runtime, da hat sich eben einiges getan - zum Positiven.

Prinzipiell solltest Du aber nicht einfach den Inhalt des Debug- oder Release-Ordners aus dem bin-Verzeichnis nehmen.
Für das, was Du machen willst, gibt es die Publish-Funktion (Rechtsklick auf das Projekt), da kannst Du mehrere Publish-Profile erstellen, z.B. eines für das Datei-System. Visual Studio erstellt dann das Programm und bereitet alles in dem eingestellten Ordner vor und alles, was da drin ist, brauchst Du dann auch.

Man kann das aber noch weiter einstellen, z.B. kannst Du Runtime und Framework selber mit liefern (self contained) oder alle managed DLLs zusammenfassen (single file) und wenn Du PDBs nicht haben willst, kann man die auch deaktivieren und so weiter.

Ganz vermeiden kann man andere Dateien aber nie, daher merke dir die Grundregel:
Alles, was in deinem publish-Ordner liegt, muss auch weitergegeben werden.
Wenn Du einzelne Dateien nicht haben willst, schau, ob es Funktionen gibt, die nicht dort abzulegen.
Wenn das nicht geht, werden sie eben benötigt.

Veröffentlichen einer .NET-Konsolenanwendung mit Visual Studio - .NET


PS @T-Virus:

Zitat von T-Virus
Die .exe allein reicht auch nicht, wenn du Abhängigkeiten zu anderen Libs (DLLs) hast.
In dem Fall ist das wahrscheinlich keine extra Abhängigkeit, sondern das Programm selber, das ja nur noch in DLLs liegt - die exe startet dann nur noch.
Daher vermutlich auch die Verwirrung - welche Abhängigkeit sollte man auch ohne Abhängigkeiten brauchen? ^^
Zitat von T-Virus
Du kannst bei den Projekten in VS 2019 schon zwischen .NET Framework und .NET Code/5 Konsolenanwendungen auswählen.
Was man allerdings nicht tun sollte! Außer man hat Abhängigkeiten, die nur mit dem alten Framework laufen.
Wenn man das freiwillig macht, verschenkt man freiwillig viele Vorteile und Verbesserungen und kettet sich freiwillig an ein altes System.

Thema: Radio Button als Gruppe abfragen
Am im Forum: Grundlagen von C#

Hat das Th69 gemeint?
Ok, dann haben wir aneinander vorbei geredet
Ich dachte, nur auf das Event von einem RadioButton horchen.

Aber klar, eine Methode an das Event von allen RadioButtons hängen, funktioniert natürlich.

Thema: Radio Button als Gruppe abfragen
Am im Forum: Grundlagen von C#

Weil bei drei oder mehr RadioButtons der Handler nicht bei jeder Änderung ausgeführt wird, der wird ja nur ausgeführt, wenn sich auch wirklich der Checked-Zustand ändert, weil bei drei oder mehr RadioButtons nicht immer der Fall ist. Bei drei RadioButtons bräuchte man also zwei Handler und bei vier Buttons braucht man drei Handler.

Oder wird der Handler von RB1 (in meinem Beispiel) auch ausgerufen, wenn er selber sich gar nicht ändert, sondern nur RB2 und RB3?

Thema: Radio Button als Gruppe abfragen
Am im Forum: Grundlagen von C#

Ok, dann habe ich dich falsch verstanden, aber das Problem bleibt.

Ich versuche es zu verdeutlichen:

RB1 => true => CheckedChanged-Handler registriert
RB2 => false
RB3 => false

Klicke ich nun auf RB2:

RB1 => false => CheckedChanged-Handler wird ausgeführt
RB2 => true
RB3 => false

Klicke ich nun auf RB3:

RB1 => false => CheckedChanged-Handler wird nicht ausgeführt
RB2 => false
RB3 => true

Und mit "auf den jeweils anderen schließen" meine ich:

RB1 => true => RB2 muss false sein
RB2 => false => RB1 muss true sein

In dem Fall würde ein CheckedChanged-Handler ausreichen, denn egal welchen der beiden Buttons ich anklicke, wird dieser Handler immer ausgeführt, weil eine Änderung immer den anderen Button betrifft. Und im Handler kann ich mir dann den Checked-Status anschauen und weiß damit automatisch den Zustand des anderen Buttons.
Aber klar, man kann ja auch einfach die Referenzen der Anderen angucken - so weit hab ich irgendwie nicht gedacht

Thema: Radio Button als Gruppe abfragen
Am im Forum: Grundlagen von C#

Das funktioniert aber nur, wenn es nur zwei RadioButtons gibt.
In dem Fall könnte man auf den jeweils Anderen schließen, aber bei 3 oder mehr geht das nicht mehr.

Thema: Radio Button als Gruppe abfragen
Am im Forum: Grundlagen von C#

Ich sähe da lieber ein FirstOrDefault + das Verhalten beim Default.
Auch wenn das beim RadioButton eigentlich nicht geht, ist der Code so etwas robuster.
Außerdem funktioniert das nur so lange, wie die Controls auch RadioButtons sind, sobald man da z.B. nochmal was drum legt, scheitert es.
Und bei so einfachen Queries würde ich die Methoden-Syntax nehmen, aber das sieht jeder anders.

Diese Art - also direkt auf die Controls zugreifen - ist aber eigentlich nur bei WinForms vernünftig.
Z.B. bei WPF und UPW gibt's MVVM und DataBinding, damit löst sich das ganze Problem aus dem Stand in Luft auf.

Thema: 5 Minuten Blöcke & Modulo innerhalb einer Stunde
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Joa - kann man drüber streiten, was besser ist. Ich finde Division intuitiver, aber naja.

Thema: 5 Minuten Blöcke & Modulo innerhalb einer Stunde
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

(i / 5) * 5

Thema: 5 Minuten Blöcke & Modulo innerhalb einer Stunde
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Dann hast Du etwas anderes falsch gemacht, die Rechnung von Th69 funktioniert.


for (var i = 0; i < 100; i++)
{
    var j = 5 * ((i % 10) / 5);
    Console.WriteLine($"{i:00} => {j:00}");
}

Thema: Via cmd Befehl in laufendes Programm schreiben
Am im Forum: Basistechnologien und allgemeine .NET-Klassen

Zitat
Wie muss ich es schreiben, dass diese Argumente in das bereits offene Programm einfließen?
Das ist deutlich komplexer

Es gibt verschiedene Wege, der heute vermutlich einfachste Weg (weil es sehr gutes Tools gibt) wäre eine Web-API, die Du aus deinem ominösen Skript-Programm heraus aufrufst.

Thema: Code soll erst auf Devops eingecheckt werden, wenn er buildet.
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Ich verstehe das Ziel dahinter, aber das würde ich auch nicht technisch erzwingen, sondern eher "soft" im Team.

Z.B. hatte ein ehemaliger Arbeitgeber von mir dafür eine kleine Tradition.
Jeder CheckIn hat einen Build angestoßen und wenn der ohne Fehler durchlief, wurde nur der Urheber informiert, wenn nicht, wurden alle informiert.
Derjenige, der zuletzt den Build "kaputt gemacht" hat, hat dann einen Plüsch-Earny als zweifelhafte Trophäe samt feierlicher Übergabe erhalten, den er solange bei sich auf dem Platz sitzen lassen musste, bis jemand Anderes den Build "kaputt gemacht" hat.

In dem Team haben es alle mit Humor genommen und mit der Zeit haben sich alle daran gewöhnt, ihre Arbeit nochmal zu kontrollieren und auch vor Feierabend darauf zu achten.
Sollte es nicht gehen (z.B. weil wirklich etwas dazwischen kam und dann nur halb-fertiger Code da war), haben viele die ShelveSets vom TFVC genutzt - die Funktion vermisse ich auch ein bisschen bei Git, die Stashes werden ja nicht auf dem Server gespeichert.

Thema: Überprüfen, ob externes Programm installiert ist
Am im Forum: Rund um die Programmierung

Das (was Th69 vorschlägt) machen übrigens viele Programme - ist die einzige mehr oder weniger zuverlässige Möglichkeit.

Z.B. gibt's Visual Studio Extensions, die externe Programme in Visual Studio integrieren. Die Extension weiß natürlich nicht, wo das Programm liegt (besonders wenn das nicht installiert werden muss), also gibt es eine Einstellung, wo man den Pfad zur exe oder zum Programm-Ordner eingeben muss.