تحديث المرجع إلى متغير عضو قيد الاستخدام

StackOverflow https://stackoverflow.com/questions/114179

  •  02-07-2019
  •  | 
  •  

سؤال

لقد حصلت على كائن ذاكرة التخزين المؤقت المفرد هذا ويكشف عن خاصية IEnumerable والتي تقوم فقط بإرجاع متغير IEnumerable خاص.

لدي طريقة ثابتة على الكائن المفرد الخاص بي الذي يقوم بتحديث متغير العضو هذا (الموجود في مثيل "المثيل" الفردي لكائن ذاكرة التخزين المؤقت هذا).

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

أعلم أنني أقوم فقط بتحديث مرجع، وترك الكائن (القديم) الآخر في الذاكرة في انتظار أن يلتقطه GC ولكن مشكلتي هي - لست متأكدًا بنسبة 100٪ مما يحدث بمجرد تعيين المرجع الجديد؟هل سيتكرر الخيط الآخر فجأة فوق الكائن الجديد أو الكائن القديم الذي تم تمريره عبر واجهة IEnumerable؟لو كان مرجعًا عاديًا لقلت "لا".سيعمل مؤشر ترابط الاستدعاء على الكائن القديم، لكنني لست متأكدًا مما إذا كان هذا هو الحال بالنسبة لـ IEnumerable أيضًا؟

وهنا تم تجريد الطبقة أسفل:

internal sealed class SektionCache : CacheBase
{
    public static readonly SektionCache Instance = new SektionCache();
    private static readonly object lockObject = new object();
    private static bool isUpdating;

    private IEnumerable<Sektion> sektioner;

    static SektionCache()
    {
        UpdateCache();
    }

    public IEnumerable<Sektion> Sektioner
    {
        get { return sektioner; }
    }

    public static void UpdateCache()
    {
    // SNIP - getting data, locking etc.
    Instance.sektioner = newSektioner;
    // SNIP
    }
}
هل كانت مفيدة؟

المحلول

سيستمر مؤشر الترابط الذي يقوم بتعداد القسم حاليًا في تعداده حتى عند تحديث المرجع داخل المفردة.لا يوجد شيء مميز فيما يتعلق بالكائنات التي تنفذ IEnumerable.

ربما ينبغي عليك إضافة متقلب الكلمة الأساسية إلى حقل sektioner لأنك لا توفر قفل القراءة وتقوم عدة سلاسل بقراءتها/كتابتها.

نصائح أخرى

منذ الحصول على { return sektioner; } يتم استدعاؤه قبل وضع القيمة الجديدة في الحقل، ويتم إرجاع القيمة القديمة.ثم الحلقة foreach (Sektion s in cache.Sektioner) يستخدم القيمة التي تم استلامها عندما تم استدعاء getter، أي.القيمة القديمة.سيتم استخدام هذه القيمة خلال حلقة foreach.

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

أعتقد أنه إذا كنت تريد سلامة الخيط، فيجب عليك استخدام هذه الطريقة:

internal sealed class SektionCache : CacheBase
{
    //public static readonly SektionCache Instance = new SektionCache();

    // this template is better ( safer ) than the previous one, for thread-safe singleton patter >>>
    private static SektionCache defaultInstance;
    private static object readonly lockObject = new object();
    public static SektionCach Default {
        get {
            SektionCach result = defaultInstance;
            if ( null == result ) {
                lock( lockObject ) {
                    if ( null == result ) {
                        defaultInstance = result = new SektionCache();
                    }
                }
            }

            return result;
        }
    }
    // <<< this template is better ( safer ) than the previous one

    //private static readonly object lockObject = new object();
    //private static bool isUpdating;
    //private IEnumerable<Sektion> sektioner;

    // this declaration is enough
    private volatile IEnumerable<Sektion> sektioner;

    // no static constructor is required >>>
    //static SektionCache()
    //{
    //    UpdateCache();
    //}
    // <<< no static constructor is required

    // I think, you can use getter and setter for reading & changing a collection
    public IEnumerable<Sektion> Sektioner {
        get {
            IEnumerable<Sektion> result = this.sektioner;
            // i don't know, if you need this functionality >>>
            // if ( null == result ) { result = new Sektion[0]; }
            // <<< i don't know, if you need this functionality
            return result;
        }
        set { this.sektion = value; }
    }

    //public static void UpdateCache()
    //{
    //// SNIP - getting data, locking etc.
    //Instance.sektioner = newSektioner;
    //// SNIP
    //}
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top