Нужно передать ссылку на ValueType в виде object, чтобы через object можно было менять содержимое структуры:
struct Point
{
public int x;
public int y;
public Point(int a, int b)
{
x = a;
y = b;
}
public void Move(int a, int b)
{
MoveObject(this, a, b);
Console.WriteLine("point from this: {0}.{1}", x, y);
}
static void MoveObject(object obj, int a, int b)
{
var p = (Point)obj;
p.x += a;
p.y += b;
Console.WriteLine("point from object: {0}.{1}", p.x, p.y);
}
}
...
public static void Main()
{
var p = new Point(1, 2);
p.Move(9, 8);
}
Сейчас в MoveObject получаем копию Point, а не ссылку на начальную структуру.
Здравствуйте, drVanо, Вы писали:
V>Нужно передать ссылку на ValueType в виде object, чтобы через object можно было менять содержимое структуры: V>
V> //Skipped
V>
V>Сейчас в MoveObject получаем копию Point, а не ссылку на начальную структуру.
Так не получится. ValueType отличается от ReferenceType тем, что хранится по месту. То есть переменная p хранится в стеке Main. А когда вы приовдите её к Object, то создаете копию структуры в куче и передаете ссылку на нее (операция называется boxing). Когда вы приводите object к Point, то создаете копию в стеке функции MoveObject, меняете её, а потом эта копия исчезает.
Вам надо воспользоваться другими способами передачи (ref, class вместо struct, возвращать копию) в зависимости от того, какой результат хотите получить.
Здравствуйте, gandjustas, Вы писали:
G>Так не получится. ValueType отличается от ReferenceType тем, что хранится по месту. То есть переменная p хранится в стеке Main. А когда вы приовдите её к Object, то создаете копию структуры в куче и передаете ссылку на нее (операция называется boxing). Когда вы приводите object к Point, то создаете копию в стеке функции MoveObject, меняете её, а потом эта копия исчезает.
Да это все понятно. Вопрос как раз в том каким образом достать указатель на ValueType из this и затем через его представление изменять свойства структуры.
Есть вот такой вариант:
public unsafe void Move(int a, int b)
{
fixed (Point* p = &this)
{
MoveObject(Pointer.Box(p, typeof(Point*)), a, b);
}
Console.WriteLine("point from this: {0}.{1}", x, y);
}
static unsafe void MoveObject(object obj, int a, int b)
{
Point* p = (Point*)Pointer.Unbox(obj);
p->x += a;
p->y += b;
Console.WriteLine("point from object: {0}.{1}", p->x, p->y);
}
Я правильно понимаю, что GC не перенесет структуру в другое место пока работает метод Point::Move иначе я не могу себе представить будет выглядеть нативный код этого дела?
Здравствуйте, Qulac, Вы писали:
Q>Здравствуйте, Serginio1, Вы писали:
S>>Здравствуйте, drVanо, Вы писали:
S>>А чем ref не подходит?
Q>MoveObject(ref this, a, b); Так тоже не работает, почему-то, структура не изменяется.
Блин напугал. Все меняется.
public void Move(int a, int b)
{
MoveObject(ref this, a, b);
Console.WriteLine("point from this: {0}.{1}", x, y);
}
static void MoveObject(ref Point p, int a, int b)
{
p.x += a;
p.y += b;
Console.WriteLine("point from object: {0}.{1}", p.x, p.y);
}
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>Здравствуйте, Qulac, Вы писали:
Q>>Здравствуйте, Serginio1, Вы писали:
S>>>Здравствуйте, drVanо, Вы писали:
S>>>А чем ref не подходит?
Q>>MoveObject(ref this, a, b); Так тоже не работает, почему-то, структура не изменяется. S>Блин напугал. Все меняется.
S>
S> public void Move(int a, int b)
S> {
S> MoveObject(ref this, a, b);
S> Console.WriteLine("point from this: {0}.{1}", x, y);
S> }
S> static void MoveObject(ref Point p, int a, int b)
S> {
S> p.x += a;
S> p.y += b;
S> Console.WriteLine("point from object: {0}.{1}", p.x, p.y);
S> }
S>
Да меняется, просто забыл про эту строчку: var p = (Point)obj;
Тут два варианта с боксингом унбоксингом и без него
public void Move(int a, int b)
{
// MoveObject(ref this, a, b);object obj = this;
MoveObject(ref obj, a, b);
this= (Point)obj;
Console.WriteLine("point from this: {0}.{1}", x, y);
}
static void MoveObject(ref object obj, int a, int b)
{
var p = (Point)obj;
p.x += a;
p.y += b;
obj = p;
Console.WriteLine("point from object: {0}.{1}", p.x, p.y);
}
static void MoveObject(ref Point p, int a, int b)
{
p.x += a;
p.y += b;
Console.WriteLine("point from object: {0}.{1}", p.x, p.y);
}
и солнце б утром не вставало, когда бы не было меня
S>>Тут два варианта с боксингом унбоксингом и без него S>>
S>> public void Move(int a, int b)
S>> {
S>> // MoveObject(ref this, a, b);
S>> object obj = this;
S>> MoveObject(ref obj, a, b);
S>> this= (Point)obj;
S>> Console.WriteLine("point from this: {0}.{1}", x, y);
S>> }
S>>
V>Дак это вы просто копируете содержимое копии обратно в this
Так в этом и заключается боксинг унбоксинг.
Приведя структуру к объекту ты создаешь новый объект. Изменяешь его и должен обратно его присвоить структуре.
public void Move(int a, int b)
{
MoveObject(ref this, a, b);
Console.WriteLine("point from this: {0}.{1}", x, y);
}
static void MoveObject(ref Point p, int a, int b)
{
p.x += a;
p.y += b;
Console.WriteLine("point from object: {0}.{1}", p.x, p.y);
}
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
V>>Дак это вы просто копируете содержимое копии обратно в this S>Так в этом и заключается боксинг унбоксинг. S>Приведя структуру к объекту ты создаешь новый объект. Изменяешь его и должен обратно его присвоить структуре.
А хотелось бы без копирования.
Я тут задавал вопрос чуть выше:
public unsafe void Move(int a, int b)
{
fixed (Point* p = &this)
{
MoveObject(Pointer.Box(p, typeof(Point*)), a, b);
}
Console.WriteLine("point from this: {0}.{1}", x, y);
}
Я правильно понимаю, что GC не может перемещать ValueType в куче пока выполняется любой из его методов (в данном случае если убрать fixed)?
Здравствуйте, drVanо, Вы писали:
V>>>Дак это вы просто копируете содержимое копии обратно в this S>>Так в этом и заключается боксинг унбоксинг. S>>Приведя структуру к объекту ты создаешь новый объект. Изменяешь его и должен обратно его присвоить структуре.
V>А хотелось бы без копирования.
V>Я тут задавал вопрос чуть выше: V>
V> public unsafe void Move(int a, int b)
V> {
V> fixed (Point* p = &this)
V> {
V> MoveObject(Pointer.Box(p, typeof(Point*)), a, b);
V> }
V> Console.WriteLine("point from this: {0}.{1}", x, y);
V> }
V>
V>Я правильно понимаю, что GC не может перемещать ValueType в куче пока выполняется любой из его методов (в данном случае если убрать fixed)?
ValueType может быть как на стеке, так и полем объекта. Он сам по себе в куче не может быть. Только его отбоксенговая копия.
Я же тебе привел пример правильного использования
public void Move(int a, int b)
{
MoveObject(ref this, a, b);
Console.WriteLine("point from this: {0}.{1}", x, y);
}
static void MoveObject(ref Point p, int a, int b)
{
p.x += a;
p.y += b;
Console.WriteLine("point from object: {0}.{1}", p.x, p.y);
}
Для не статика
public void MoveObject(int a, int b)
{
this.x += a;
this.y += b;
Console.WriteLine("point from object: {0}.{1}", this.x, this.y);
}
Здравствуйте, drVanо, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Так не получится. ValueType отличается от ReferenceType тем, что хранится по месту. То есть переменная p хранится в стеке Main. А когда вы приовдите её к Object, то создаете копию структуры в куче и передаете ссылку на нее (операция называется boxing). Когда вы приводите object к Point, то создаете копию в стеке функции MoveObject, меняете её, а потом эта копия исчезает.
V>Да это все понятно. Вопрос как раз в том каким образом достать указатель на ValueType из this и затем через его представление изменять свойства структуры.
this — это и есть "указатель" на ValueType.
V>Есть вот такой вариант: V>
V> public unsafe void Move(int a, int b)
V> {
V> fixed (Point* p = &this)
V> {
V> MoveObject(Pointer.Box(p, typeof(Point*)), a, b);
V> }
V> Console.WriteLine("point from this: {0}.{1}", x, y);
V> }
V> static unsafe void MoveObject(object obj, int a, int b)
V> {
V> Point* p = (Point*)Pointer.Unbox(obj);
V> p->x += a;
V> p->y += b;
V> Console.WriteLine("point from object: {0}.{1}", p->x, p->y);
V> }
V>
Вариант есть, но он вам не нужен. V>Я правильно понимаю, что GC не перенесет структуру в другое место пока работает метод Point::Move иначе я не могу себе представить будет выглядеть нативный код этого дела?
Нет, GC не перенесёт структуру в другое место, пока исполнение не выйдет из блока fixed{}. Есть там метод Move или нет — неважно.
Непонятно, зачем вы делаете эту ерунду.
1. Если вы решили пердолиться с поинтерами, то можно просто вот так:
public unsafe void Move(int a, int b)
{
fixed (Point* p = &this)
{
MoveObject(p, a, b);
}
Console.WriteLine("point from this: {0}.{1}", x, y);
}
static unsafe void MoveObject(Point *p, int a, int b)
{
p->x += a;
p->y += b;
Console.WriteLine("point from object: {0}.{1}", p->x, p->y);
}
2. По-прежнему непонятно, зачем пердолиться с указателями и ансейфом, когда можно просто
public void Move(int a, int b)
{
MoveObject(ref this, a, b);
}
static unsafe void MoveObject(ref Point p, int a, int b)
{
p.x += a;
p.y += b;
Console.WriteLine("point from object: {0}.{1}", p.x, p.y);
}
Задачу-то вы какую решаете?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Задачу-то вы какую решаете?
Рискну предполдожить, что у топикстартера есть разные типы структур, которые хочется (или нужно) менять в одном единственном методе и передавать эти структуры соответственно приходится унифицированно через "object".
Тогда мог бы подойти свой "Variant" c ref-ссылками разного типа.
P.S.
S>2. По-прежнему непонятно, зачем пердолиться с указателями и ансейфом, когда можно просто
S>staticunsafevoid MoveObject(ref Point p, int a, int b)
S>{
S> p.x += a;
S> p.y += b;
S> Console.WriteLine("point from object: {0}.{1}", p.x, p.y);
S>}
Это очевидно опечатка и unsafe выше не нужен.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали: _FR>Рискну предполдожить, что у топикстартера есть разные типы структур, которые хочется (или нужно) менять в одном единственном методе и передавать эти структуры соответственно приходится унифицированно через "object". _FR>Тогда мог бы подойти свой "Variant" c ref-ссылками разного типа.
Да, нужна будет ref struct и ref scoped параметр такого метода.
Но это всё выглядит крайне странно. Например, если бы мне потребовалось, скажем, унифицированно менять поле x в структурах разных типов, то очевидным решением является вот такое:
public interface IXSettable
{
public int X{get;set;}
}
public struct Point: IXSettable
{
int x;
int y;
int X {get => x; set => x = value; }
}
public struct IntWrapper: IXSettable
{
public IntWrapper(int v) => x = v;
private int x;
public int X {get => x; set => x = value; }
}
public static void MoveX<T>(ref T t)
where T: IXSettable, struct
=> t.X += 1;
public static void Main()
{
var p = new Point(); (p.x, p.y) = (17, 42);
MoveX(ref p);
var w = IntWrapper(x);
MoveX(ref w);
}
_FR>P.S. _FR>Это очевидно опечатка и unsafe выше не нужен.
Да, конечно, правил по месту.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, Sinclair, Вы писали:
S>>Задачу-то вы какую решаете?
_FR>Рискну предполдожить, что у топикстартера есть разные типы структур, которые хочется (или нужно) менять в одном единственном методе и передавать эти структуры соответственно приходится унифицированно через "object". _FR>Тогда мог бы подойти свой "Variant" c ref-ссылками разного типа.
Здравствуйте, _FRED_, Вы писали:
S>>Задачу-то вы какую решаете?
_FR>Рискну предполдожить, что у топикстартера есть разные типы структур, которые хочется (или нужно) менять в одном единственном методе и передавать эти структуры соответственно приходится унифицированно через "object". _FR>Тогда мог бы подойти свой "Variant" c ref-ссылками разного типа.
Почти угадали. Мы занимаемся разработкой продукта, который позволяет "вируализировать" CIL команды и выполнять их на собственном интерпретаторе. Поэтому есть проблема с передачей ref аргументов (в том числе и this у ValueType) в унифицированном виде. Сейчас это выглядит так:
public void Move(int a, int b)
{
object[] array = new object[]
{
this,
a,
b
};
try
{
new VirtualMachine().Invoke(array, 10809);
}
finally
{
this = (Program.Point)array[0];
}
}
Здравствуйте, drVanо, Вы писали:
S>>Если ему нужна рефлексия, то варианты здесь S>>How to invoke methods with ref/out params using reflection in C#?
V>Рефлексия нужна, но она будет использоваться ниже по стеку, когда this уже невиден.
Ты лучше объясни, что тебе надо.
Есть дженерики с ref where T:struct
Если ты хочешь сайд эффект, то моё мнение проще копировать. То есть боксить к объекту изменять свойства и копировать в this
Так или иначе рефлексия занимает намного больше, чем выигрыш на поинтерах и прочих эмитах итд
и солнце б утром не вставало, когда бы не было меня