C# memcpy эквивалент

У меня есть 2 объекта одного типа, и я хотел бы поверхностно скопировать одно состояние в другое. В C++ у меня есть memcpy, и это здорово. Как я могу сделать это в C#? MemberwiseClone() недостаточно хорош, потому что он создает и возвращает новый объект, и мне нравится копировать в существующий объект. Я думал об использовании отражения, но я боюсь, что это будет слишком медленно для производственного кода. Я также думал об использовании одного из сериализаторов.Net, но я думаю, что они также создают объект, а не устанавливают существующий.

Мой вариант использования:

У меня есть объект шаблона (класс не структура), который должен быть обновлен одним из его экземпляров (объекты, сделанные из этого шаблона)

Есть идеи?

9 ответов

Решение

[править] относительно вашего пояснения: Как я понимаю, у вас есть N объектов, у каждого есть (прямая) ссылка на объект шаблона. Вы хотите написать обратно в шаблон, чтобы все объекты "увидели" эти изменения.

Предложение: реализовать шаблон брокера.

class TemplateProvider
{
   public MyData Template { get; set; }
}

Вместо того, чтобы передавать шаблон, передайте поставщик шаблона объектам.

Чтобы просто определить синтаксис в компонентах, вы можете добавить свойство (личное / внутреннее?)

MyData Template { get { return m_templateProvider.Template; } }
void UpdateTemplate() { m_templateProvider.Template = 
                            (MyData) this.MemberwiseClone(); }

Поставщик шаблонов также упрощает блокировку в многопоточных сценариях.


Короче говоря, ни за что, если вы не сделаете это сами. Но почему бы не создать новый объект, если вы все равно переопределите все свойства?

memcopy и подобные низкоуровневые конструкции не поддерживаются, поскольку они подрывают гарантии, предоставляемые окружающей средой.

Мелкая копия для структур сделана по назначению. Для занятий MemberwiseClone это способ сделать это - но, как вы говорите, создает новый объект.

Для этого нет встроенного способа, и, поскольку он потенциально нарушает инкапсуляцию, его следует использовать с осторожностью.

Вы можете создать общую подпрограмму, используя отражение, но будет ли она работать или нет, зависит от самого класса. И да, это будет сравнительно медленно.

Осталось только поддержать его пользовательским интерфейсом. Вы можете предоставить стандартную подпрограмму "Мелкое копирование", которая проверяет интерфейс и использует его, а затем возвращает к отражению, когда этого не происходит. Это делает функциональность доступной в целом, и вы можете оптимизировать классы, для которых производительность важна позже.

В C# (И в C++ тоже), нет никакой разницы между "новым объектом" и "копией существующего объекта", если все их элементы равны друг другу.

Дано:

Int32 a = 5;

, обе операции:

Int32 b = 5;
Int32 b = a;

дать тот же результат.

Как указано в справке MSDN:

Метод MemberwiseClone создает поверхностную копию, создавая новый объект, а затем копируя нестатические поля текущего объекта в новый объект.

Если поле является типом значения, выполняется побитовая копия поля.

Если поле является ссылочным типом, ссылка копируется, а ссылочный объект - нет; следовательно, исходный объект и его клон ссылаются на один и тот же объект.

то есть он делает так же, как memcpy() в C++

namespace WindowsFormsApplication7
{

    [Serializable] // just put this in your class
    class Mate
    {
        public string SomeProperty { get; set; }
    }

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();


            var mA = new Mate();
            mA.SomeProperty = "Hey";

            var vf = new BinaryFormatter();
            var ns = new MemoryStream();
            vf.Serialize(ns, mA);
            byte[] vytes = ns.ToArray();


            var vfx = new BinaryFormatter();
            var nsx = new MemoryStream();            
            nsx.Write(vytes, 0, vytes.Length);
            nsx.Seek(0, 0);
            var mB = (Mate)vfx.Deserialize(nsx);

            mA.SomeProperty = "Yo";

            MessageBox.Show(mA.SomeProperty); // Yo
            MessageBox.Show(mB.SomeProperty); // Hey
        }
    }
}

Эквивалент memcpy в C # / .Net - Buffer.MemoryCopy .

      void MemoryCopy (void* source, void* destination, long destinationSizeInBytes, long sourceBytesToCopy);

https://docs.microsoft.com/en-us/dotnet/api/system.buffer.memorycopy?view=net-5.0

namespace WindowsFormsApplication7
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            var dt = new DataTable();
            dt.Columns.Add("lastname", typeof(string));
            dt.Columns.Add("firstname", typeof(string));

            dt.Rows.Add("lennon", "john");
            dt.Rows.Add("mccartney", "paul");


            var ms = new MemoryStream();
            var bf = new BinaryFormatter();
            bf.Serialize(ms, dt);
            byte[] bytes = ms.ToArray();



            var bfx = new BinaryFormatter();
            var msx = new MemoryStream();
            msx.Write(bytes, 0, bytes.Length);
            msx.Seek(0, 0);


            // doesn't just copy reference, copy all contents
            var dtx = (DataTable)bfx.Deserialize(msx);


            dtx.Rows[0]["lastname"] = "Ono";


            // just copy reference
            var dty = dt;

            dty.Rows[0]["lastname"] = "Winston";

            MessageBox.Show(dt.Rows[0]["lastname"].ToString()); // Winston
            MessageBox.Show(dtx.Rows[0]["lastname"].ToString()); // Ono
            MessageBox.Show(dty.Rows[0]["lastname"].ToString()); // Winston

        }
    }
}

Я думаю, вы могли бы просто сделать что-то вроде:

YourObjectType A = new YourObjectType();
YourObjectType B = a.MemberwiseClone();

Это создаст новый объект внутри метода MemberwiseClone и заставит объект B ссылаться на него. Я думаю, что это служит вашим целям.

Присвоение одной структуры другой для всех намерений и целей работает точно так же, как memcpy в C++ на объектах POD.

Если вы чувствуете, что это не применимо в вашей ситуации, то я могу заверить вас, что ваш код C++ не соответствовал стандартам (то есть содержал ошибки в форме неопределенного поведения). Пожалуйста, укажите (в вопросе), какого эффекта вы хотите достичь. Это будет более полезно, чем говорить о репликации неопределенного поведения на другом языке.

Я не могу использовать вновь созданный объект, потому что мне нравится, когда объект шаблона изменяется в соответствии с состоянием одного из его экземпляров (то есть, экземпляр сделан из этого шаблона)

Когда я думаю об этом - очень интересно взглянуть на код реализации метода MemberWiseClone() и посмотреть, как Microsoft решила мой вопрос.

Другие вопросы по тегам