Konvertieren von Ruby in C #

7

Sie müssen den folgenden Code von Ruby in C # konvertieren. Ich bin jedoch etwas verwirrt über die Verwendung des Yield-Schlüsselwortes und der allgemeinen Syntax von Ruby. Kann jemand, der ein bisschen Ruby kennt, bitte helfen und den Code umwandeln

%Vor%

Ende

    
flalar 13.04.2009, 17:11
quelle

4 Antworten

12

Ich kenne C # überhaupt nicht, also sollte alles, was ich über C # sage, mit einem Körnchen Salz eingenommen werden. Ich werde jedoch versuchen zu erklären, was in diesem Teil des Ruby-Codes vor sich geht.

%Vor%

Ruby hat etwas namens Singleton-Methoden . Diese haben nichts mit dem Singleton Software Design Pattern zu tun, sie sind nur Methoden, die für ein und nur ein Objekt definiert sind. Sie können also zwei Instanzen derselben Klasse verwenden und Methoden zu einem dieser beiden Objekte hinzufügen.

Es gibt zwei verschiedene Syntaxen für Singleton-Methoden. Zum einen wird dem Objekt der Name der Methode vorangestellt, sodass def foo.bar(baz) nur für das Objekt bar eine Methode foo definiert. Die andere Methode heißt und öffnet die Singleton-Klasse und ähnelt syntaktisch der Definition einer Klasse, da dies auch semantisch geschieht: Singleton-Methoden leben tatsächlich in einer unsichtbaren Klasse, die zwischen das Objekt und seine eingefügt wird aktuelle Klasse in der Klassenhierarchie.

Diese Syntax sieht folgendermaßen aus: class << foo . Dies öffnet die Singleton-Klasse des Objekts foo und jede in diesem Klassen-Body definierte Methode wird zu einer Singleton-Methode des Objekts foo .

Warum wird das hier benutzt? Nun, Ruby ist eine reine objektorientierte Sprache, was bedeutet, dass alles , einschließlich Klassen, ein Objekt ist. Wenn nun Methoden zu einzelnen Objekten hinzugefügt werden können und Klassen Objekte sind, können Methoden zu einzelnen Klassen hinzugefügt werden. Mit anderen Worten, Ruby braucht keine künstliche Unterscheidung zwischen regulären Methoden und statischen Methoden (was ohnehin ein Betrug ist: es sind keine wirklichen Methoden, nur verherrlichte Prozeduren). Was ist eine statische Methode in C #, ist nur eine normale Methode für die Singleton-Klasse eines Klassenobjekts.

All dies ist nur eine langwierige Erklärung dafür, dass alles, was zwischen class << Cache und seinem entsprechenden end definiert ist, static wird.

%Vor%

In Ruby ist jede Variable, die mit einem Großbuchstaben beginnt, tatsächlich eine Konstante. In diesem Fall werden wir diese jedoch nicht als static const -Felder, sondern als enum übersetzen, weil sie so verwendet werden.

%Vor%

Diese Methode hat drei Parameter (vier sehen wir eigentlich warum später), zwei davon sind optional ( ttl und generation_time ). Beide haben einen Standardwert, aber im Fall von ttl wird der Standardwert nicht wirklich verwendet, er dient eher als Markierung, um herauszufinden, ob das Argument übergeben wurde oder nicht.

30.seconds ist eine Erweiterung, die die ActiveSupport -Bibliothek der Klasse Integer hinzufügt. Es tut eigentlich nichts, es gibt nur self zurück. Es wird in diesem Fall nur verwendet, um die Methodendefinition lesbarer zu machen. (Es gibt andere Methoden, die etwas Nützlicheres tun, z. B. Integer#minutes , das self * 60 und Integer#hours usw. zurückgibt.) Wir werden dies als Hinweis darauf verwenden, dass der Typ des Parameters nicht int sein sollte. aber eher System.TimeSpan .

%Vor%

Dies enthält mehrere komplexe Ruby-Konstrukte. Fangen wir mit dem einfachsten an: Nachlaufende bedingte Modifikatoren. Wenn ein bedingter Text nur einen Ausdruck enthält, kann die Bedingung an das Ende des Ausdrucks angehängt werden. Anstatt also if a > b then foo end zu sagen, kannst du auch foo if a > b sagen. Also, das obige ist äquivalent zu unless ttl then return get(key) { yield } end .

Der nächste ist auch einfach: unless ist nur syntaktischer Zucker für if not . Also, wir sind jetzt bei if not ttl then return get(key) { yield } end

Drittens ist Rubys Wahrheitssystem. In Ruby ist die Wahrheit ziemlich einfach. Tatsächlich ist Falschheit ziemlich einfach und die Wahrheit fällt natürlich aus: Das spezielle Schlüsselwort false ist falsch, und das spezielle Schlüsselwort nil ist falsch, alles andere ist wahr. In diesem Fall ist also die Bedingung nur wahr, wenn ttl entweder false oder nil ist. false ist für eine Zeitspanne kein fürchterlich vernünftiger Wert, also ist der einzige interessante% nil . Das Snippet wäre klarer wie folgt geschrieben worden: if ttl.nil? then return get(key) { yield } end . Da der Standardwert für den Parameter ttl nil ist, ist diese Bedingung wahr, wenn für ttl kein Argument übergeben wurde. Also wird die Bedingung verwendet, um herauszufinden, mit wie vielen Argumenten die Methode aufgerufen wurde, was bedeutet, dass wir sie nicht als eine bedingte, sondern als eine Methodenüberladung übersetzen werden.

Nun zum yield . In Ruby kann jede Methode einen impliziten Codeblock als Argument akzeptieren. Deshalb habe ich oben geschrieben, dass die Methode tatsächlich vier Argumente annimmt, nicht drei. Ein Codeblock ist nur ein anonymer Codeabschnitt, der weitergegeben, in einer Variablen gespeichert und später aufgerufen werden kann. Ruby erbt Blöcke von Smalltalk, aber das Konzept reicht bis 1958 zurück zu Lisp's Lambda-Ausdrücken. Bei der Erwähnung anonymer Codeblöcke, aber zumindest jetzt, sollten Sie bei der Erwähnung von Lambda-Ausdrücken wissen, wie Sie diesen impliziten vierten Methodenparameter darstellen: einen Delegattyp, genauer gesagt, ein Func .

Also, was macht yield ? Es überträgt die Kontrolle an den Block.Es ist im Grunde nur eine sehr bequeme Möglichkeit, einen Block aufzurufen, ohne ihn explizit in einer Variablen speichern und dann aufrufen zu müssen.

%Vor%

Diese #{foo} -Syntax wird String-Interpolation genannt. Es bedeutet "ersetzen Sie das Token innerhalb der Zeichenfolge mit dem Ergebnis der Auswertung des Ausdrucks zwischen den geschweiften Klammern". Es ist nur eine sehr prägnante Version von String.Format() , und genau das werden wir in das Programm übersetzen.

%Vor%

Dies ist mein schwacher Versuch, die Ruby-Version in C # zu übersetzen:

%Vor%

Bitte beachten Sie, dass ich C # nicht kenne, .NET nicht. Ich habe das nicht getestet, ich weiß nicht einmal, ob es syntaktisch gültig ist. Hoffe es hilft trotzdem.

    
Jörg W Mittag 13.04.2009, 19:14
quelle
5

Es scheint, dass diesem Code ein Block zur Auswertung übergeben wird, wenn der Cache die angeforderten Daten nicht enthält ( yield ist der Aufruf des Blocks). Dies ist ziemlich idiomatischer Ruby-Code; Ich weiß nicht, wie (oder auch wenn) du es in c # übersetzen könntest.

Suchen Sie nach einem Anwendungsfall, um zu sehen, was ich meine. Sie sollten etwas vage wie folgt finden:

%Vor%

Besser wäre es, herauszufinden, was Sie tun müssen, und etwas zu schreiben, das de novo in c # tut, anstatt zu versuchen, von Ruby zu "übersetzen".

    
MarkusQ 13.04.2009 17:17
quelle
4

Es sieht so aus, als ob Sie versuchen, memcache-client von Ruby nach C # zu portieren. Wenn dies der Fall ist, könnte es einfacher sein, eine native C # memcache-Clientimplementierung zu verwenden, beispielsweise:

Ссылка

Wie auch immer, ich stimme MarkusQ im Allgemeinen zu, dass das Übersetzen von einer höheren in eine untere Sprache wahrscheinlich insgesamt weniger produktiv sein wird, als nur das idiomatische Umschreiben der Zielsprache. Eine direkte Übersetzung von Ruby nach C # wird Ihnen im besten Fall einen sehr hässlichen Code geben.

Mit dem yield-Schlüsselwort Ruby können Sie einen Codeblock aufrufen, der als implizit deklariertes Argument an die Methode übergeben wurde. So können Sie sich zum Beispiel die Smart_get-Methodendefinition so vorstellen, als ob sie eher wie folgt aussieht:

%Vor%

Und wenn Sie smart_get als solches aufrufen:

%Vor%

Der Kram in den geschweiften Klammern wird dem Variablenblock in der obigen erweiterten Definition zugewiesen. yield ruft dann den Code in & amp; block auf. Dies ist eine grobe Vereinfachung, aber sollte Ihnen helfen, die allgemeine Idee zu bekommen.

Zurück zu Ihrer Conversion Die Vereinfachung, die ich gerade gemacht habe, wird Sie nicht unbedingt 100% ig dorthin bringen, denn sobald Sie einen C # -Weg finden, diesen Code zu übersetzen, wird ein anderer Code Ihre Übersetzung zerstören. Nehmen wir an, eine bestimmte Methode muss den Block überprüfen:

%Vor%

Und da Lambdas in Ruby erstklassige Objekte sind, können Sie auf Code wie den folgenden stoßen:

%Vor%

Und dann helfe Gott Ihnen, wenn Sie auf Code stoßen, der Methoden on the fly definiert, oder (schlechter für einen Übersetzer) Vorteile von Rubys formbaren Klassen nutzt:

%Vor%

Da jede Instanz jeder Klasse in Ruby eine eigene Klassendefinition haben kann, bin ich nicht wirklich sicher, wie man auch einfache Beispiele ohne ausgefallene Gymnastik in C # portieren würde. Ruby hat viele dieser Funktionen, die einen einfachen Übersetzungsaufwand unterbrechen. Daher würde ich empfehlen, das zu lernen, was Sie portieren möchten, und es dann von Grund auf neu zu erstellen.

    
runako 13.04.2009 17:56
quelle
0

Versuchen Sie Folgendes:

%Vor%     
user3342029 22.02.2014 23:11
quelle

Tags und Links