سؤال

لدينا التطبيق الذي يقوم بإجراء مقارنات على كائنات البيانات لتحديد ما إذا كان إصدار واحد من وجوه مختلفة من الآخر.التطبيق لدينا أيضا بعض الواسعة التخزين المؤقت من هذه الكائنات ، و لقد واجهت قليلا من الأداء مشكلة عندما يتعلق الأمر إلى القيام بهذه المقارنات.

وهنا سير العمل:

  1. بيانات البند 1 البند الحالي في الذاكرة.وكان هذا البند في البداية استردادها من ذاكرة التخزين المؤقت العميق المستنسخة (دون الكائنات مثل القواميس الخ).بيانات البند 1 ثم تحريرها ، وخصائصه يتم تعديلها.
  2. نحن ثم مقارنة هذا الكائن ضد النسخة الأصلية التي تم تخزينها في ذاكرة التخزين المؤقت.وبما أن البيانات البند 1 المستنسخة و خصائصه تغيير هذه الكائنات يجب أن تكون مختلفة.

وهناك زوجين من القضايا هنا.

القضية الرئيسية هي العميق استنساخ الطريقة مكلفة جدا.لقد وصفنا ضد الضحلة استنساخ وكان 10x أبطأ.هذا هراء.هنا لدينا طريقة استنساخ العميق:

    public object Clone()    
    {
        using (var memStream = new MemoryStream())
        {
            var binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
            binaryFormatter.Serialize(memStream, this); 
            memStream.Seek(0, SeekOrigin.Begin);
            return binaryFormatter.Deserialize(memStream);
        }
    }

كنا في البداية باستخدام التالية إلى استنساخ:

public object Clone()
{
    return this.MemberwiseClone();
}

كان هذا أكثر performant ، ولكن لأنه لا الضحلة استنساخ جميع الكائنات المعقدة التي كانت خصائص هذا الكائن مثل القواميس وما إلى ذلك ، لم تكن المستنسخة.الكائن لا تزال تحتوي على نفس مرجع الكائن في ذاكرة التخزين المؤقت ، وبالتالي فإن خصائص سيكون نفس عند المقارنة.

هل من أحد لديه طريقة فعالة للقيام عميق استنساخ على C# من الأشياء التي من شأنها أن تغطي استنساخ الكائن بأكمله البيانية ؟

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

المحلول

أنت لن تكون قادرة على الحصول على أفضل بكثير من عامة ثنائي التسلسل صراحة دون تنفيذ ICloneable على جميع البيانات الخاصة بك من الأشياء التي تحتاج إلى أن تكون المستنسخة.ممكن آخر الطريق هو انعكاس, ولكنك لن تكون سعيدا معها إما إذا كنت تبحث عن الأداء.

وأود أن تنظر في اتخاذ ضرب مع ICloneable عميق نسخ و/أو IComparable لمقارنة إذا كانت الأشياء مختلفة ...إذا كان الأداء الكبير مشكلة بالنسبة لك.

نصائح أخرى

وربما كنت لا ينبغي أن استنساخ العميق بعد ذلك ؟

خيارات أخرى:

1) جعل "مؤقتا" كائن تذكر حالته الأصلية و جعل ذلك تحديث "تغيير" العلم في كل مرة تغير أي شيء.

2) لا تذكر الأصلية الدولة فقط العلم كائن قذر مرة واحدة لم يتغير أي شيء من أي وقت مضى.ثم تحديث كائن من المصدر الأصلي للمقارنة.أراهن على الأشياء الخاصة بك تغيير في كثير من الأحيان أقل من لا تغيير, وحتى أقل من ذلك في كثير من الأحيان تغيير مرة أخرى إلى نفس القيمة.

فمن الممكن أن ردي قد لا تنطبق على حالتك لأنني لا أعرف ماذا قيود الشرط ، ولكن شعوري هذا الغرض العام الاستنساخ قد يكون مشكلة.كما كنت قد واجهت بالفعل ، قد يكون أداء قضية.شيء يحتاج إلى تحديد حالات فريدة من نوعها في كائن الرسم البياني ومن ثم إنشاء نسخة طبق الأصل.هذا هو ما مسلسل ثنائي لا لك ، ولكن ذلك أيضا لا أكثر (التسلسل نفسه).أنا لا استغرب أن أرى أنه أبطأ مما هو متوقع.لدي تجربة مماثلة (وبالمناسبة أيضا ذات الصلة التخزين المؤقت).توجهي تنفيذ الاستنساخ من قبل نفسي ، أيتنفيذ IClonnable عن الطبقات التي في الواقع تحتاج إلى أن تكون المستنسخة.كم عدد الطبقات هناك في التطبيق الخاص بك التي كنت التخزين المؤقت ؟ إذا كان هناك الكثير من (يدويا رمز الاستنساخ) ، من شأنه أن يجعل المعنى إلى النظر في بعض التعليمات البرمجية الجيل ؟

يمكنك جعل العميق الاستنساخ بطريقتين:من خلال تنفيذ ICloneable (بأنه كائن.MemberwiseClone طريقة) ، أو عن طريق ثنائي التسلسل.

الطريقة الأولى

أول (وربما أسرع ، ولكن ليس دائما أفضل) طريقة تنفيذ ICloneable واجهة في كل نوع.يوضح النموذج أدناه.الفئة C تنفذ ICloneable ، لأن هذه الفئة المراجع الأخرى الطبقات D و E ، ثم ترس أيضا تنفيذ هذه الواجهة.داخل استنساخ طريقة ج ، ندعو استنساخ طريقة من أنواع أخرى.

Public Class C
Implements ICloneable

    Dim a As Integer
    ' Reference-type fields:
    Dim d As D
    Dim e As E

    Private Function Clone() As Object Implements System.ICloneable.Clone
        ' Shallow copy:
        Dim copy As C = CType(Me.MemberwiseClone, C)
        ' Deep copy: Copy the reference types of this object:
        If copy.d IsNot Nothing Then copy.d = CType(d.Clone, D)
        If copy.e IsNot Nothing Then copy.e = CType(e.Clone, E)
        Return copy
    End Function
End Class

Public Class D
Implements ICloneable

    Public Function Clone() As Object Implements System.ICloneable.Clone
        Return Me.MemberwiseClone()
    End Function
End Class

Public Class E
Implements ICloneable

    Public Function Clone() As Object Implements System.ICloneable.Clone
        Return Me.MemberwiseClone()
    End Function
End Class

الآن عند استدعاء استنساخ طريقة مثيل ج ، يمكنك الحصول على أعماق استنساخ هذا المثال:

Dim c1 As New C
Dim c2 As C = CType(c1.Clone, C)   ' Deep cloning.  c1 and c2 point to two different 
                                   ' locations in memory, while their values are the 
                                   ' same at the moment.  Changing a value of one of
                                   ' these objects will NOT affect the other.

ملاحظة:إذا الطبقات D و E مرجع أنواع ، يجب تنفيذ استنساخ الطريقة كما فعلنا الفئة C.وهلم جرا.

تحذيرات:1-عينة أعلاه صالحة طالما لا يوجد مرجع دائري.فعلى سبيل المثال ، إذا class C الذاتي المرجعية (على سبيل المثال ، وهو الحقل الذي هو من نوع ج) تنفيذ ICloneable واجهة لن تكون سهلة ، استنساخ طريقة في ج قد أدخل حلقة لا نهاية لها.

2-شيء آخر هو أن نلاحظ أن MemberwiseClone الطريقة المحمية طريقة فئة الكائن.هذا يعني أنه يمكنك استخدام هذه الطريقة فقط من داخل رمز الطبقة كما هو موضح أعلاه.وهذا يعني أنه لا يمكنك استخدامه الخارجية الطبقات.

وبالتالي تنفيذ ICloneable صالحة فقط عندما اثنين من التحذيرات أعلاه لا وجود لها.وإلا يجب عليك استخدام ثنائي التسلسل تقنية.

الطريقة الثانية

ثنائي التسلسل يمكن أن تستخدم العميق الاستنساخ دون المشاكل المذكورة أعلاه (وخاصة مرجع دائري).وهنا عامة الأسلوب الذي ينفذ في أعماق الاستنساخ باستخدام ثنائي التسلسل:

Public Class Cloning
    Public Shared Function DeepClone(Of T)(ByVal obj As T) As T
        Using MStrm As New MemoryStream(100)    ' Create a memory stream.
            ' Create a binary formatter:
            Dim BF As New BinaryFormatter(Nothing, New StreamingContext(StreamingContextStates.Clone))

            BF.Serialize(MStrm, obj)    ' Serialize the object into MStrm.
            ' Seek the beginning of the stream, and then deserialize MStrm:
            MStrm.Seek(0, SeekOrigin.Begin)
            Return CType(BF.Deserialize(MStrm), T)
        End Using
    End Function
End Class

وفيما يلي كيفية استخدام هذا الأسلوب:

Dim c1 As New C
Dim c2 As C = Cloning.DeepClone(Of C)(c1)   ' Deep cloning of c1 into c2.  No need to 
                                            ' worry about circular references!
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top