2010-04-18 11 views
6

Es gibt eine well known issue, wenn es um die Verwendung von .NET-Werttypen in IronPython geht. Dies hat mir kürzlich Kopfschmerzen bereitet, als ich versuchte, Python als eingebettete Skriptsprache in C# zu verwenden. Das Problem lässt sich wie folgt zusammenfassen:Wie behandelt man Wertetypen beim Einbetten von IronPython in C#?

eine C# struct wie Gegeben:

struct Vector { 
    public float x; 
    public float y; 
} 

Und eine C# Klasse wie:

class Object { 
    public Vector position; 
} 

Im Folgenden wird in Ironpython passieren:

Wie der Artikel sagt, bedeutet dies, dass Werttypen meist unveränderlich sind. Dies ist jedoch ein Problem, da ich eine Vektorbibliothek verwenden wollte, die wie oben beschrieben implementiert ist. Gibt es Workarounds für die Arbeit mit vorhandenen Bibliotheken, die Werttypen verwenden? Das Ändern der Bibliothek wäre der allerletzte Ausweg, aber das würde ich lieber vermeiden.

+0

Funktioniert das? obj = Object() pos = Vector() pos.x = 1 obj.position = pos Druck obj.position.x –

+0

Ja, das funktioniert. Mit einem geeigneten Konstruktor kann man auch 'obj.position = Vector (1,0)' verwenden. Dies könnte akzeptabel sein, obwohl das Verhalten, das ich in meiner Frage beschrieben habe, immer noch verwirrend wäre ... – kloffy

Antwort

4

Es gibt keine Notwendigkeit, die Bibliothek zu ändern, nur einen Proxy verwenden.

struct Vector { 
    public float X; 
    public float Y; 
} 

class BetterVector { 
    public float X; 
    public float Y; 
    public Vector Optimized { get { return new Vector(X, Y); } } 
} 

class Object { 
    public BetterVector Position { get; set; } 
} 

Nun ist die Python-Code kann Felder als normal eingestellt und der Code kann Optimized aufrufen, wenn es um die Daten zu OpenGL oder XNA füttern muss oder was auch immer Sie verwenden.

Sie können sogar implizite Zwang verwenden, wenn Optimized Aufruf wie zu viel Arbeit scheint:

class BetterVector { 
    // ... 
    public static implicit operator Vector(BetterVector v) { 
     return v.Optimized; 
    } 
} 
+0

Das ist ziemlich cool, vor allem mit dem impliziten Zwang. Man müsste eine Reihe von Proxies schreiben, aber es sollte nicht zu viel Arbeit sein. Ich lasse die Frage für ein wenig mehr offen, nur um zu sehen, ob es andere Vorschläge gibt, aber ich mag diesen Ansatz. – kloffy

2

Wenn Sie anrufen

obj.position.x = 1

Was man bekommt, ist, dass das Objekt obj eine Instanz der Position Struktur erhält, die es im Wesentlichen eine Kopie macht, so, Einstellung Der X-Wert wird nicht fortgeschrieben.

Was Sie sagen, ist, dass obj.position = Vector (1,0) ist, was Sie tun sollten. Ähnliche Dinge passieren in C#.


Bearbeiten - möglich Arbeit um.

Wenn Sie nicht wollen, den Konstruktor einzurichten, glaube ich, das wird funktionieren:

obj = Object() 
pos = obj.position; # gets the object 
pos.x = 1 
pos.y = 2 
obj.position = pos # I'm not sure if this line is necessary 
+0

Nun, ja und nein. Ich verstehe das Konzept der Wertetypen und kann die Schwierigkeiten erkennen, die sie bei der Übersetzung von IronPython haben. Die aktuelle Lösung unterscheidet sich jedoch vom Verhalten in C# (wie im verknüpften Artikel erwähnt) und unterscheidet sich von der Funktionsweise von Python (die keine Werttypen hat). Wenn IronPython so etwas wie eine 'getattref'-Funktion hätte, würde es den Benutzern ermöglichen, das C# -Verhalten neu zu erstellen, was, soweit ich es beurteilen kann, momentan nicht möglich ist. – kloffy

+0

Ja, C# ist anders, aber das Verhalten ist ähnlich. Ich habe meine Antwort aktualisiert, das könnte ein wenig besser funktionieren. – McKay

+0

Das ist kein schlechter Weg, es syntaktisch ähnlich aussehen zu lassen, aber ich frage mich, ob es eine Möglichkeit gibt, die gleiche Semantik wie in C# zu erhalten (dh kein neue Kopie von Vector). – kloffy

1

Der einzige Weg, die ich gefunden habe structs zu aktualisieren ist die Tatsache zunutze zu machen, dass Sie keinen öffentlichen Bereich angeben/property beim Erstellen einer Struktur. Die Syntax sieht wie benannte/optionale Parameter in Python aus.

namespace StructExample 
{ 
    public struct MyStruct 
    { 
     public int x; 
     public int y { get; set; } 
    } 

    public class MyClass 
    { 
     public MyStruct a; 
    } 
} 

Wir können die Klassen in Ironpython wie folgt verwenden:

>>> foo = MyClass() 
>>> print "%d:%d" % (foo.a.x, foo.a.y) 
0:0 
>>> foo.a.x = 1 # doesn't work! 
>>> print "%d:%d" % (foo.a.x, foo.a.y) 
0:0 
>>> foo.a = MyStruct(x=1,y=2) 
>>> print "%d:%d" % (foo.a.x, foo.a.y) 
1:2 

Es wäre schön, wenn Python eine Syntax wie die F # ‚mit‘ hatte eine neue Struktur für das Erstellen, Kopieren Sie die Felder aus der alte. Leider müssen wir beim Klonen einer Struktur alle Felder angeben.

+0

Danke für die Erwähnung des Kwargs-Konstruktors, das kann sehr praktisch sein. – kloffy

-1

Eher rätselhaft, dass Sie in so einer Ecke gelandet sind. In Python (versucht, dies auf Ironpython 2.6.1, .Net 4.0) der entsprechende Code dazu wäre:

>>> class a: 
... x = 0 
... y = 0 
... 
>>> class b: 
... Vector = a() 
... 
>>> c = b() 
>>> c.Vector.x = 1 
>>> print c.Vector.x 
1 

Hinweis gibt einen Unterschied zwischen meinem Pseudo-Code ist und bei Ihnen - statische Eigenschaft ist eine Instanz eines zugewiesen Klasse, nicht nur mit Typdefinition verlassen. Als Nebeneffekt wird eine tatsächliche Instanz einer Klasse als b.Vector initialisiert, wenn b instanziiert wird.

(Der Pseudo-Code ist immer noch "broken" - die Initialisierung in def init gehen muss (Selbst-), ​​aber das ist eine andere Geschichte)

Die Moral von der beispielsweise statt „public Vector verlassen Position "nicht initialisiert, Build-Initialisierung von" Position "in Klasse Objekt.

+0

Vielen Dank für Ihren Kommentar. Ich denke jedoch nicht, dass es anwendbar ist, weil ich über .NET-Werttypen sprach. Mir ist bewusst, dass Sie das gleiche Problem nicht nur mit IronPython-Klassen auftreten. – kloffy

Verwandte Themen