سؤال

لدي كائنين من نفس النوع وأرغب في نسخ حالة واحدة إلى أخرى.في C++ لدي memcpy وهو أمر رائع.كيف يمكنني أن أفعل ذلك في C#؟إن MemberwiseClone () ليس جيدًا بما يكفي لأنه يقوم بإنشاء وإرجاع كائن جديد وأحب النسخ إلى كائن موجود.فكرت في استخدام الانعكاس ولكني أخشى أن يكون بطيئًا جدًا بالنسبة لرمز الإنتاج.لقد فكرت أيضًا في استخدام أحد برامج تسلسل .Net ولكني أعتقد أنها تقوم أيضًا بإنشاء كائن بدلاً من تعيين كائن موجود.

حالة الاستخدام الخاصة بي:

لدي كائن قالب (فئة وليست بنية) يحتاج إلى التحديث بواسطة إحدى مثيلاته (الكائنات المصنوعة من هذا القالب)

أيه أفكار؟

هل كانت مفيدة؟

المحلول

[عدل] بخصوص توضيحك:كما أفهم، لديك كائنات 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 هي الطريقة للقيام بذلك - ولكن كما تقول فإن ذلك يُنشئ كائنًا جديدًا.

لا توجد طريقة مدمجة لذلك، وبما أنه من المحتمل أن يؤدي ذلك إلى كسر التغليف، فيجب استخدامه بحذر على أي حال.

يمكنك بناء روتين عام باستخدام الانعكاس، ولكن نجاحه أم لا يعتمد على الفصل نفسه.ونعم، سوف تكون بطيئة نسبيا.

ما تبقى هو دعمه من خلال واجهة مخصصة.يمكنك توفير روتين "Shallow Copy" عام يتحقق من الواجهة ويستخدمها، ويعود إلى الانعكاس عندما لا يحدث ذلك.وهذا يجعل الوظيفة متاحة بشكل عام، ويمكنك تحسين الفئات التي يكون الأداء مهمًا لها لاحقًا.

نصائح أخرى

في C# (و في C++ أيضًا)، لا يوجد فرق بين "كائن جديد" و"نسخة من كائن موجود" طالما أن جميع أعضائهما متساويان مع بعضهما البعض.

منح:

Int32 a = 5;

, كلا العمليتين:

Int32 b = 5;
Int32 b = a;

تسفر عن نفس النتيجة.

كما جاء في مرجع MSDN:

يقوم أسلوب MemberwiseClone بإنشاء نسخة سطحية عن طريق إنشاء كائن جديد، ثم نسخ الحقول غير الثابتة للكائن الحالي إلى الكائن الجديد.

إذا كان الحقل عبارة عن نوع قيمة، فسيتم إجراء نسخة من الحقل خطوة بخطوة.

إذا كان الحقل عبارة عن نوع مرجع، فسيتم نسخ المرجع ولكن الكائن المشار إليه لا يتم نسخه؛لذلك، يشير الكائن الأصلي واستنساخه إلى نفس الكائن.

, ، أي.يفعل نفس الشيء memcpy() في C++

أعتقد أنه يمكنك فعل شيء مثل:

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

سيؤدي هذا إلى إنشاء كائن جديد داخل أسلوب MemberwiseClone وجعل الكائن B مرجعًا له.أعتقد أنه يخدم أغراضك.

إن إسناد بنية إلى أخرى، لجميع المقاصد والأغراض، يعمل بالضبط يحب memcpy في C++ على كائنات POD.

إذا شعرت أن هذا لا ينطبق على موقفك، فيمكنني أن أؤكد لك أن كود 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
        }
    }
}
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

        }
    }
}

لا أستطيع استخدام كائن تم إنشاؤه حديثًا لأنني أحب نموذج الكائن الذي سيتم تغييره وفقًا لحالة أحد مثيلاته (أي مثيل مصنوع من هذا القالب)

عندما أفكر في الأمر - من المثير للاهتمام جدًا إلقاء نظرة على كود تنفيذ طريقة MemberWiseClone() ومعرفة كيف قامت Microsoft بحل سؤالي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top