Как обработать типы значения при встраивании IronPython в C#?

Существует известная проблема когда дело доходит до использования типов значения.NET в IronPython. Это недавно вызвало меня головная боль при попытке использовать Python в качестве встроенного языка сценариев в C#. Проблеме можно подвести итог следующим образом:

Учитывая структуру C#, такую как:

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

И класс C#, такой как:

class Object {
    public Vector position;
}

Следующее произойдет в IronPython:

obj = Object()
print obj.position.x    # prints ‘0’
obj.position.x = 1
print obj.position.x    # still prints ‘0’

Как в статье говорится, это означает, что типы значения главным образом неизменны. Однако это - проблема, поскольку я был планированием пользования векторной библиотекой, которая реализована, как замечено выше. Есть ли какие-либо обходные решения для работы с существующими библиотеками, которые полагаются на типы значения? Изменение библиотеки было бы самым последним курортом, но я скорее избегу этого.

6
задан kloffy 18 April 2010 в 23:12
поделиться

4 ответа

Нет необходимости изменять библиотеку, просто используйте прокси.

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; }
}

Теперь код Python может устанавливать поля как обычно, и ваш код может вызывать Optimized , когда ему нужно передать данные в OpenGL или XNA или что-то еще, что вы используете.

Вы даже можете использовать неявное принуждение, если вызов Optimized кажется слишком трудоемким:

class BetterVector {
   // ...
   public static implicit operator Vector(BetterVector v) {
       return v.Optimized;
   }
}
4
ответ дан 17 December 2019 в 02:26
поделиться

Когда вы вызываете

obj.position.x = 1

Вы получаете то, что объект obj получает экземпляр структуры позиции, которую он фактически копирует, поэтому, устанавливая значение X не распространяется.

Вы говорите, что obj.position = Vector (1,0) - это то, что вам следует делать. Аналогичные вещи происходят в C #.


Edit - возможен обходной путь.

Если вы не хотите настраивать конструктор, я считаю, что это сработает:

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
2
ответ дан 17 December 2019 в 02:26
поделиться

Я нашел единственный способ обновить структуры - это использовать тот факт, что вы можете указать любое публичное поле / свойство при создании структуры. Синтаксис выглядит как именованные / необязательные параметры в Python.

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

    public class MyClass
    {
        public MyStruct a;
    }
}

Мы можем использовать классы в IronPython следующим образом:

>>> 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

Было бы неплохо, если бы у Python был синтаксис наподобие F # 'with' для создания новой структуры, копирования полей из старой. К сожалению, при клонировании структуры нам приходится указывать все поля.

1
ответ дан 17 December 2019 в 02:26
поделиться

Непонятно, что вы оказались в таком углу. В python (пробовал это на IronPython 2.6.1, .Net 4.0) эквивалентный код будет примерно таким:

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

Обратите внимание, есть одно различие между моим псевдокодом и вашим - статическому свойству присваивается экземпляр класса, а не только осталось с определением типа. В качестве побочного эффекта фактический экземпляр класса инициализируется как b.Vector при создании экземпляра b.

(Псевдокод все еще "сломан" - инициализация должна идти в def init (self), но это другая история)

Мораль примера, вместо того, чтобы оставить " public Vector position "неинициализирован, встроить инициализацию" position "в класс Object.

-1
ответ дан 17 December 2019 в 02:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: