Greifen Sie auf catch zu, wenn alles im try-Block bereits abgefangen wurde

19

Dies ist durch die Syntax, die ich vermute, auf Java und C # beschränkt.

In diesem Programmierrätsel musst du Exceptions produzieren , die gefangen werden können, aber am Ende des Fangblocks erneut geworfen werden.

try
{
    while(true)
        try
        {
            // you are only allowed to modify code between this try { } brackets
        }
        catch(Exception ex2) {  }
}
catch(Exception ex1)
{
    // your goal is to reach this catch block by modifying the code ...
    // in the inner try block above
    // You win if you reach this part and execute on of the following code lines
    Console.WriteLine("You won!"); // for C#
    // Or
    System.out.println("You won!"); // for Java
}

Sie können Code vor und nach diesem Snippet frei einfügen.

Der kürzeste Code, um den äußeren catchBlock zu erreichen , gewinnt.

user21634
quelle
1
Ich denke, Python kann auch mithalten.
User12205
1
Sie können Code frei vor und nach meinem Snippet einfügen.
user21634
2
Schade, dass es geschlossen ist. Ich habe eine Lösung . An @algorithmshark, Michael und Jan Dvorak: Dies ist KEINE allgemeine Programmierfrage. Es ist ein Programmierpuzzle, ähnlich wie Wann ist eine Giraffe keine Giraffe? . Ich nenne dies für die Wiedereröffnung.
user12205
1
Uhhhhhh, Whaaat ???
TheDoctor
1
@algorithmshark Ich würde mit der Summe der Längen der Einfügungen gehen
user12205

Antworten:

24

C #, 46 (88 einschließlich Boilerplate)

using System;class P{static void Main(){
        try
        {
            while(true)
                try
                {
                    System.Threading.Thread.CurrentThread.Abort();
                }
                catch(Exception ex2) {  }
        }
        catch(Exception ex1)
        {
            // your goal is to reach this catch block by modifying the code ...
            // in the inner try block above
            // You win if you reach this part and execute on of the following code lines
            Console.WriteLine("You won!"); // for C#
        }
}}

Die Abort()Methode löst eine ThreadAbortException aus , eine spezielle Ausnahme, die am Ende jedes catch-Blocks automatisch erneut ausgelöst wird (sofern sie nicht Thread.ResetAbort()aufgerufen wird).

BenM
quelle
20

C # 24 Zeichen

Beendet den inneren Try-Block, bevor er beabsichtigt ist, sodass ich eine Ausnahme außerhalb des Try-Blocks auslösen kann.

}finally{int a=1/0;}try{
rdans
quelle
1
Mann das ist genial! Warum habe ich nicht daran gedacht? (Übrigens können Sie es verkürzen, indem Sie tatsächlich eine Ausnahme auslösen, anstatt eine Ausnahme int a=1/0;
auszulösen
Brauchst du int a=da In einigen Sprachen können Sie einfach den Ausdruck schreiben1/0
Gnibbler 13.11.14
Dies ist kein vollständiges Beispiel, oder? Die 24 Zeichen zählen also nicht ...
Matt
13

Java, 76 oder 31

Zählt nur die im Code vorgenommenen Einfügungen und ignoriert dabei neue Zeilen. 76, wenn Sie alles zählen, was ich hinzugefügt habe, 31, wenn Sie die erste und die letzte Zeile ausschließen, dh nur zählen int a=1/0;try{}catch(Error e){}.

class P{public static void main(String[]A){
try
{
    while(true)
        try
        {
            int a=1/0;try{
        }
        catch(Exception ex2) {  }
}
catch(Exception ex1)
{
    // your goal is to reach this catch block by modifying the code ...
    // in the inner try block above
    // You win if you reach this part and execute on of the following code lines
    //Console.WriteLine("You won!"); // for C#
    // Or
    System.out.println("You won!"); // for Java
}
}catch(Error e){}
}}
user12205
quelle
Ups, sorry, ich habe nicht darauf geachtet, wie du gezählt hast. Ich werde meine Antwort aktualisieren, um die andere Zählmethode hinzuzufügen. Ich denke, es ist besser, nur die Zeichen im try-Block zu zählen, da wir sonst im Grunde C # mit Java-Boilerplate vergleichen würden. Dies kann jedoch kompliziert werden, wenn jemand eine Antwort mit einem wichtigen Code außerhalb des try-Blocks sendet (wie dies nach den Regeln zulässig ist).
BenM
@BenM Keine Sorge, und ich verstehe, warum du es so gezählt hast. Es ist nur so, dass das OP nicht spezifiziert hat, wie zu zählen ist, also dachte ich, ich würde beides einschließen.
user12205
Sehr clevere Lösung.
Nicolas Barbulesco
@NicolasBarbulesco Ehrlich gesagt finde ich die Antwort von Ryan schlauer als meine. Schließlich habe ich nach dem Snippet einen catchBlock hinzugefügt , was er nicht tat.
user12205
3

Warnung : Diese Programme sind Klonbomben (eine Art weniger gefährliche, aber immer noch gefährliche Form einer Gabelbombe). als solche, laufen sie nicht auf einem Produktivsystem ohne Sandbox oder Ressourcengrenzen . Klonbomben erzeugen Threads in einer Schleife (im Gegensatz zu Gabelbomben, die Prozesse in einer Schleife erzeugen). Sie können sie also einfach stoppen, indem Sie den betreffenden Prozess beenden (was sie viel weniger gefährlich macht als Gabelbomben, die sehr schwer zu handhaben sind klären); Aber sie werden wahrscheinlich den größten Teil Ihrer CPU belasten, bis Sie das schaffen (oder bis das Programm von selbst gewinnt und von selbst beendet wird). Wenn Sie Ihr Betriebssystem auffordern, die Größe des Arbeitsspeichers und die CPU-Zeit, die diese Programme verwenden dürfen, zu begrenzen, sollten Sie eine sichere Umgebung zum Testen dieser Programme schaffen.

Java (OpenJDK 8) , 65 bis 60 Byte (mit einer geringfügigen Änderung am Wrapper)

Thread x=Thread.currentThread();new Thread(x::stop).start();

Probieren Sie es online!

Erfordert, dass beide Instanzen von catch (Exception …)in der Frage in geändert werden catch (Throwable …). Dies sollte in der Theorie mehr sicher, nicht weniger, aber es ermöglicht diese Lösung möglich zu sein.

Ich habe 5 Bytes gegenüber der ersten Version dieser Antwort gespart, indem ich eine Methodenreferenz anstelle eines Lambda verwendet habe.

Java 4, 104 Byte (ungetestet, sollte mit dem Original-Wrapper funktionieren)

final Thread x=Thread.currentThread();new Thread(){public void run(){x.stop(new Exception());}}.start();

Probieren Sie es online! (Link geht zu einer Java 8-Implementierung, funktioniert also nicht)

Mithilfe von Funktionen, die aus modernen Java-Versionen entfernt wurden, kann sogar die Version des Puzzles gelöst werden, für die eine erforderlich ist Exception. Zumindest wahrscheinlich. (Java 4 ist mittlerweile sehr alt und ich kann mich nicht erinnern, welche Funktionen es enthielt und welche nicht. Wie man sieht, gab es damals in Java viel weniger Funktionen und diese waren daher ausführlicher; wir hatten keine Lambdas, also musste ich eine innere Klasse schaffen.)

Erklärungen

Die meisten Lösungen für diese Frage sind in C # (zusammen mit einer Java-Lösung, die über die Verwendung von unsymmetrischen Klammern als Form der Code-Injection täuscht, und einer Perl-Lösung, die ebenfalls nicht in Java enthalten ist). Daher hielt ich es für sinnvoll, zu zeigen, wie dieses Rätsel auch in Java "richtig" gelöst werden kann.

Beide Programme sind praktisch identisch (die Tatsache, dass das erste Programm funktioniert, gibt mir die Gewissheit, dass das zweite Programm auch funktioniert, es sei denn, ich habe versehentlich eine Nicht-Java-4-Funktion verwendet, Thread#stopdie in Java 5 veraltet war).

Javas Thread#stopMethode funktioniert hinter den Kulissen, indem ein Wurfobjekt in den fraglichen Thread geworfen wird. Das für diesen Zweck vorgesehene Wurfobjekt ist ThreadDeath( Errorinsbesondere, weil die Leute oft versuchen, Ausnahmen zu überdecken und Javas Designer dies nicht wollten), obwohl Sie damit irgendwann nach der API alles werfen können (oder es gewohnt waren) Javas Designer erkannten, dass dies eine unglaublich schlechte Idee war, und entfernten die Version der Methode, die Argumente direkt in die Hand nimmt. Natürlich ist selbst die Version, die wirft, ThreadDeatheine ziemlich riskante Operation, für die Sie nur wenige Garantien abgeben können (zum Beispiel können Sie damit dieses Rätsel lösen, was "nicht" möglich sein sollte, also sollten Sie es nicht tun benutze es, aber ab Java 8 funktioniert es immer noch.

Dieses Programm erzeugt einen neuen Thread und fordert ihn auf, eine Ausnahme zwangsweise in den Haupt-Thread zurück zu werfen. Wenn wir Glück haben, geschieht dies zu einem Zeitpunkt, an dem wir außerhalb des inneren catchBlocks sind (wir können den äußeren catchBlock nicht verlassen, bis das Programm endet, da es eine Schleife gibt). Da wir die Schleife bereits hinzugefügt haben, ist es Byte-sparend, diese Schleife einfach zu verwenden, damit wir weiterhin Threads erstellen können, in der Hoffnung, dass einer von ihnen irgendwann das richtige Timing erreicht. Dies scheint normalerweise innerhalb weniger Sekunden zu geschehen.

(Hinweis zu TIO: Die aktuelle Version von TIO ist sehr geneigt, dieses Programm zu einem frühen Zeitpunkt seiner Ausführung abzubrechen, vermutlich weil alle Threads erstellt wurden. Es kann mit TIO funktionieren, funktioniert jedoch nicht zuverlässig, weshalb häufig einige Versuche erforderlich sind Holen Sie sich die Ausgabe "Sie haben gewonnen!".)

ais523
quelle
1

C #

    try
    {
        int i = 0, j = 1, k;

        int flag = 0;
        lbl:
        if (flag == 1)
        {
            k = j / i;
        }

        while (true)
            try
            {
                k = j / i;

            }
            catch (Exception e)
            {
                flag = 1;
                goto lbl;
                //Console.WriteLine("loose");

            }
    }
    catch (Exception e)
    {
        Console.WriteLine("Won");

    }
Devendra
quelle
1
Willkommen bei Programming Puzzles & Code Golf! Da es sich bei dieser Frage um eine Code-Golf- Herausforderung handelt, versuchen Sie bitte, Ihren Code so kurz wie möglich zu halten und geben Sie die Anzahl der Zeichen oben in Ihre Antwort ein. Vielen Dank!
ProgramFOX
1

Perl 5 , 37 oder 36 Bytes

eval {
    while (1) {
        eval {

 

use overload'""',sub{die};die bless[]

 

        };
        $@ eq "" or 0;
    }
};
$@ eq "" or print "You won!\n";

Probieren Sie es online!

Es stellt sich heraus, dass diese Frage gut genug in Perl übersetzt wird, um auch dort ein interessantes Rätsel zu machen. Perls tryÄquivalent heißt (etwas verwirrend) evalund gibt eine Ausnahme an, indem es @_auf eine Ausnahme gesetzt wird, wenn sie aufgetreten ist, und ansonsten auf die Nullzeichenfolge. Als solches wird ein catchBlock durch Vergleichen @_mit der Nullzeichenfolge implementiert .

Diese Lösung erstellt ein Objekt (dessen Klasse das gesamte Programm ist; Sie können beliebige Perl-Dateien wie Klassen verwenden, ähnlich wie die Umkehrung von Java (wobei Sie beliebige Klassen wie Dateien verwenden können)). Das ist der bless[]Teil ( blessnormalerweise erscheint er nur tief in Konstruktoren, als das Grundelement, das Dinge in erster Linie zu Objekten macht, aber Sie können ihn direkt verwenden, wenn Sie wirklich wollen), []der Speicherzuweiser für das Objekt - in diesem Fall ein Listenkonstruktor case - und die Klasse wird nicht angegeben, daher wird angenommen, dass es sich um die aktuell ausgeführte handelt). In der Zwischenzeit geben wir unserer "Klasse" (dh der Hauptdatei) eine benutzerdefinierte Methode zum Vergleichen mit einer Zeichenfolge über use overloadund lassen diese Methode eine Ausnahme auslösen (wodurch die Schleife verlassen und das Rätsel gelöst wird). wir können das tatsächlich setzenuse overloadÜberall, und obwohl es traditionell mit den anderen Methodendefinitionen übereinstimmt und sich dem oberen Rand der Datei nähert, können wir es in die Lücke setzen, die wir stattdessen erhalten haben, und es funktioniert immer noch. (Wenn wir es am Ende der Datei einfügen, könnten wir das Semikolon danach weglassen, was zu einer 36-Byte-Lösung führt, aber dies ist wohl ein Betrug, da es davon abhängt, dass das Programm an erster Stelle ein abschließendes Semikolon hat nicht garantiert.) Es ist tatsächlich kürzer, den Stringify-Vorgang zu überladen und Perl einen Stringvergleich daraus automatisch generieren zu lassen, als einen Stringvergleich direkt zu überladen (da das Überladen einiger Operatoren Sie dazu zwingt, auch andere Operatoren zu überladen).

Jetzt müssen wir nur noch unser Objekt mit werfen die. Die evalendet, dann , wenn wir zu vergleichen , versuchen , $@auf die Null - Zeichenfolge (um zu sehen , ob es eine Ausnahme), wirft der Vergleich eine weitere Ausnahme und wir außen entweichen eval.


quelle