7

我有 2 个相同类型的对象,我想将一种状态浅复制到另一种状态。在 C++ 中,我有很棒的 memcpy。我怎么能在 C# 中做到这一点?MemberwiseClone() 不够好,因为它创建并返回一个新对象,我喜欢复制到现有对象。我想过使用反射,但我担心它对于生产代码来说太慢了。我也想过使用.Net 序列化程序之一,但我认为它们也会创建对象而不是设置现有对象。

我的用例:

我有一个模板对象(类而不是结构),它需要由它的一个实例(由该模板制成的对象)更新

有任何想法吗?

4

9 回答 9

6

C#(以及在C++)中,“新对象”和“现有对象的副本”之间没有区别,只要它们的所有成员彼此相等。

鉴于:

Int32 a = 5;

, 两种操作:

Int32 b = 5;
Int32 b = a;

产生相同的结果。

MSDN 参考中所述:

MemberwiseClone 方法通过创建一个新对象,然后将当前对象的非静态字段复制到新对象来创建浅拷贝。

如果字段是值类型,则执行该字段的逐位复制。

如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其克隆引用同一个对象。

,即它的作用memcpy()C++

于 2009-02-04T11:43:36.930 回答
4

[编辑] 关于您的说明:据我了解,您有 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是执行此操作的方法-但正如您所说,这会创建一个新对象。

没有内置的方法,因为它可能会破坏封装,所以无论如何都应该小心使用。

您可以使用反射构建一个通用例程,但它是否有效取决于类本身。是的,ti 会比较慢。

剩下的是通过自定义界面支持它。您可以提供一个通用的“浅拷贝”例程来检查接口并使用它,并在没有时回退到反射。这使得该功能普遍可用,并且您可以在以后优化性能重要的类。

于 2009-02-04T11:48:12.927 回答
2
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
        }
    }
}
于 2009-02-04T14:33:25.650 回答
1

我想你可以这样做:

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

这将在 MemberwiseClone 方法中创建一个新对象,并使 B 对象引用它。我想它符合你的目的。

于 2009-02-04T11:45:33.713 回答
1

出于所有意图和目的,将一个结构分配给另一个结构的工作方式与 C++ 中的 POD 对象完全一样memcpy

如果您觉得这不适用于您的情况,那么我可以向您保证您的 C++ 代码不符合标准(即,包含未定义行为形式的错误)。请指定(在问题中)您想要达到的效果。这将比谈论用另一种语言复制未定义的行为更有用。

于 2009-02-04T13:51:24.427 回答
1
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

        }
    }
}
于 2009-02-04T14:41:30.673 回答
0

我不能使用新创建的对象,因为我喜欢根据其中一个实例的状态来更改模板对象(即由该模板构成的实例)

于 2009-02-04T13:46:00.410 回答
0

当我想到它时 - 查看 MemberWiseClone() 方法实现的代码并了解 Microsoft 如何解决我的问题非常有趣。

于 2009-02-04T13:48:28.143 回答
0

C# / .Net memcpy 等效为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

于 2021-05-17T10:12:05.297 回答