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 решила мой вопрос.