Передать this в виде object
От: drVanо Россия https://vmpsoft.com
Дата: 14.03.24 09:27
Оценка:
Нужно передать ссылку на 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, а не ссылку на начальную структуру.
Отредактировано 14.03.2024 9:28 drVanо . Предыдущая версия .
Re: Передать this в виде object
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 14.03.24 09:38
Оценка: 1 (1) +2
Здравствуйте, drVanо, Вы писали:

V>Нужно передать ссылку на ValueType в виде object, чтобы через object можно было менять содержимое структуры:

V>
V>   //Skipped
V>


V>Сейчас в MoveObject получаем копию Point, а не ссылку на начальную структуру.


Так не получится. ValueType отличается от ReferenceType тем, что хранится по месту. То есть переменная p хранится в стеке Main. А когда вы приовдите её к Object, то создаете копию структуры в куче и передаете ссылку на нее (операция называется boxing). Когда вы приводите object к Point, то создаете копию в стеке функции MoveObject, меняете её, а потом эта копия исчезает.

Вам надо воспользоваться другими способами передачи (ref, class вместо struct, возвращать копию) в зависимости от того, какой результат хотите получить.
Re[2]: Передать this в виде object
От: drVanо Россия https://vmpsoft.com
Дата: 14.03.24 11:59
Оценка:
Здравствуйте, 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 иначе я не могу себе представить будет выглядеть нативный код этого дела?
Отредактировано 14.03.2024 12:04 drVanо . Предыдущая версия . Еще …
Отредактировано 14.03.2024 12:03 drVanо . Предыдущая версия .
Отредактировано 14.03.2024 12:02 drVanо . Предыдущая версия .
Отредактировано 14.03.2024 12:02 drVanо . Предыдущая версия .
Re: Передать this в виде object
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 14.03.24 16:38
Оценка:
Здравствуйте, drVanо, Вы писали:

А чем ref не подходит?
и солнце б утром не вставало, когда бы не было меня
Re[2]: Передать this в виде object
От: Qulac Россия  
Дата: 14.03.24 16:46
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, drVanо, Вы писали:


S>А чем ref не подходит?


MoveObject(ref this, a, b); Так тоже не работает, почему-то, структура не изменяется.
Программа – это мысли спрессованные в код
Отредактировано 14.03.2024 16:48 Qulac . Предыдущая версия .
Re[3]: Передать this в виде object
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 14.03.24 17:55
Оценка: 1 (1)
Здравствуйте, 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);
 }
и солнце б утром не вставало, когда бы не было меня
Re[4]: Передать this в виде object
От: Qulac Россия  
Дата: 14.03.24 18:06
Оценка: :)
Здравствуйте, 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;
Программа – это мысли спрессованные в код
Re: Передать this в виде object
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 15.03.24 10:27
Оценка:
Здравствуйте, drVanо, Вы писали:

Тут два варианта с боксингом унбоксингом и без него
   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);
      }
и солнце б утром не вставало, когда бы не было меня
Re[2]: Передать this в виде object
От: drVanо Россия https://vmpsoft.com
Дата: 15.03.24 10:49
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Здравствуйте, drVanо, Вы писали:


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>


Дак это вы просто копируете содержимое копии обратно в this
Re[3]: Передать this в виде object
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 15.03.24 10:53
Оценка:
Здравствуйте, drVanо, Вы писали:


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

Так в этом и заключается боксинг унбоксинг.
Приведя структуру к объекту ты создаешь новый объект. Изменяешь его и должен обратно его присвоить структуре.

Упаковка-преобразование и распаковка-преобразование

Интересные моменты в C# (boxing unboxing)


Не хочешь боксинга используй ref структуры

 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);
 }
и солнце б утром не вставало, когда бы не было меня
Отредактировано 15.03.2024 10:56 Serginio1 . Предыдущая версия . Еще …
Отредактировано 15.03.2024 10:54 Serginio1 . Предыдущая версия .
Re[4]: Передать this в виде object
От: drVanо Россия https://vmpsoft.com
Дата: 15.03.24 10:59
Оценка:
Здравствуйте, 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)?
Отредактировано 15.03.2024 11:01 drVanо . Предыдущая версия . Еще …
Отредактировано 15.03.2024 11:00 drVanо . Предыдущая версия .
Re[5]: Передать this в виде object
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 15.03.24 11:22
Оценка:
Здравствуйте, 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);
 }


Почитай еще

ref locals и ref returns в C#: подводные камни производительности
и солнце б утром не вставало, когда бы не было меня
Отредактировано 15.03.2024 13:37 Serginio1 . Предыдущая версия . Еще …
Отредактировано 15.03.2024 11:26 Serginio1 . Предыдущая версия .
Re[3]: Передать this в виде object
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.03.24 15:23
Оценка:
Здравствуйте, 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);
            }



Задачу-то вы какую решаете?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Передать this в виде object
От: _FRED_ Черногория
Дата: 15.03.24 17:03
Оценка: +2
Здравствуйте, Sinclair, Вы писали:

S>Задачу-то вы какую решаете?


Рискну предполдожить, что у топикстартера есть разные типы структур, которые хочется (или нужно) менять в одном единственном методе и передавать эти структуры соответственно приходится унифицированно через "object".
Тогда мог бы подойти свой "Variant" c ref-ссылками разного типа.

P.S.

S>2. По-прежнему непонятно, зачем пердолиться с указателями и ансейфом, когда можно просто

S>static unsafe 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>}

Это очевидно опечатка и unsafe выше не нужен.
Help will always be given at Hogwarts to those who ask for it.
Отредактировано 15.03.2024 17:16 _FRED_ . Предыдущая версия .
Re[5]: Передать this в виде object
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.03.24 10:09
Оценка:
Здравствуйте, _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 выше не нужен.
Да, конечно, правил по месту.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Передать this в виде object
От: romangr Россия  
Дата: 16.03.24 10:30
Оценка:
Здравствуйте, drVanо, Вы писали:

V>Нужно передать ссылку на ValueType в виде object, чтобы через object можно было менять содержимое структуры:


Что-то похожее делают тут
... << RSDN@Home 1.3.110 alpha 5 rev. 62>>
Re[5]: Передать this в виде object
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 17.03.24 16:08
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, Sinclair, Вы писали:


S>>Задачу-то вы какую решаете?


_FR>Рискну предполдожить, что у топикстартера есть разные типы структур, которые хочется (или нужно) менять в одном единственном методе и передавать эти структуры соответственно приходится унифицированно через "object".

_FR>Тогда мог бы подойти свой "Variant" c ref-ссылками разного типа.

Если ему нужна рефлексия, то варианты здесь
How to invoke methods with ref/out params using reflection in C#?
и солнце б утром не вставало, когда бы не было меня
Отредактировано 17.03.2024 16:10 Serginio1 . Предыдущая версия .
Re[5]: Передать this в виде object
От: drVanо Россия https://vmpsoft.com
Дата: 18.03.24 11:50
Оценка: 126 (1)
Здравствуйте, _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];
    }
}
Отредактировано 18.03.2024 11:53 drVanо . Предыдущая версия . Еще …
Отредактировано 18.03.2024 11:51 drVanо . Предыдущая версия .
Re[6]: Передать this в виде object
От: drVanо Россия https://vmpsoft.com
Дата: 18.03.24 11:55
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>Если ему нужна рефлексия, то варианты здесь

S>How to invoke methods with ref/out params using reflection in C#?

Рефлексия нужна, но она будет использоваться ниже по стеку, когда this уже невиден.
Re[7]: Передать this в виде object
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 18.03.24 12:08
Оценка: +2
Здравствуйте, drVanо, Вы писали:

S>>Если ему нужна рефлексия, то варианты здесь

S>>How to invoke methods with ref/out params using reflection in C#?

V>Рефлексия нужна, но она будет использоваться ниже по стеку, когда this уже невиден.

Ты лучше объясни, что тебе надо.
Есть дженерики с ref where T:struct
Если ты хочешь сайд эффект, то моё мнение проще копировать. То есть боксить к объекту изменять свойства и копировать в this
Так или иначе рефлексия занимает намного больше, чем выигрыш на поинтерах и прочих эмитах итд
и солнце б утром не вставало, когда бы не было меня
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.