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

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

  •  09-06-2019
  •  | 
  •  

سؤال

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

الملفات عبارة عن إصدارات متسلسلة بتنسيق XML لأربعة فئات تستخدمها الأداة (دعنا نسميها A وB وC وD).تشكل الفصول هيكل شجرة عندما يكون كل شيء على ما يرام.يعمل محررنا عن طريق تحميل مجموعة من الملفات، وإلغاء تسلسلها، والعمل على العلاقات بينها، وتتبع أي حالات سيئة يمكنه العثور عليها.الفكرة هي أن نبتعد عن التحرير اليدوي لهذه الملفات، الأمر الذي يؤدي إلى حدوث الكثير من الأخطاء.

بالنسبة لنوع معين من الأخطاء، أرغب في الاحتفاظ بمجموعة من كافة الملفات التي بها المشكلة.يمكن أن تواجه جميع الفئات الأربعة المشكلة، وأرغب في تقليل تكرار التعليمات البرمجية قدر الإمكان.أحد المتطلبات المهمة هو أن المستخدم يجب أن يكون قادرًا على الحصول على العناصر في مجموعات؛على سبيل المثال، يحتاجون إلى الحصول على جميع الكائنات A مع وجود خطأ، وإخبارهم بالتكرار على المجموعة بأكملها واختيار ما يريدون هو أمر غير مقبول مقارنة بـ GetAs() طريقة.لذا، كانت فكرتي الأولى هي إنشاء عنصر عام يرتبط بالكائن الذي تم إلغاء تسلسله وبعض البيانات الوصفية للإشارة إلى الخطأ:

public class ErrorItem<T>
{
    public T Item { get; set; }
    public Metadata Metadata { get; set; }
}

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

لا يرث أي من الطبقات من سلف مشترك (بخلاف Object).ربما كان هذا خطأ في التصميم الأولي، لكنني أمضيت بضعة أيام في التفكير في الأمر ولم يكن لدى الفصول الدراسية الكثير من القواسم المشتركة بخلاف خاصية GUID التي تحدد كل عنصر بشكل فريد حتى أتمكن من معرفة سبب المصمم الأصلي ولم يربطهم بالميراث.وهذا يعني أن مجموعة الأخطاء الموحدة ستحتاج إلى تخزينها ErrorItem<Object> الكائنات، نظرًا لأنه ليس لدي فئة أساسية أو واجهة لتقييد ما يأتي.ومع ذلك، فإن هذا يجعل فكرة هذه المجموعة الموحدة سطحية بعض الشيء بالنسبة لي:

Public Class ErrorCollection
{
    public ErrorItem<Object> AllItems { get; set; }
}

ومع ذلك، فإن هذا له عواقب على الواجهة العامة.ما أريده حقا هو العودة المناسبة ErrorItem نوع عام مثل هذا:

public ErrorItem<A>[] GetA()

هذا مستحيل لأنني لا أستطيع إلا أن أخزن ErrorItem<Object>!لقد قمت بمراجعة بعض الحلول في رأسي.في الغالب أنها تتضمن إنشاء ملف جديد ErrorItem من النوع المناسب سريعًا، لكنه يبدو قبيحًا نوعًا ما.فكرة أخرى كانت تستخدم أ Dictionary للحفاظ على العناصر منظمة حسب النوع، ولكن لا يزال هذا لا يبدو صحيحًا.

هل هناك نوع من النمط الذي قد يساعدني هنا؟أعلم أن أسهل طريقة لحل هذه المشكلة هي إضافة فئة أساسية تشتق منها A وB وC وD، لكنني أحاول أن يكون لها تأثير بسيط على الأداة الأصلية قدر الإمكان.هل تكلفة أي حل بديل كبيرة بما يكفي لكي أضغط لتغيير الأداة الأولية؟

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

المحلول

إذا لم يكن هناك أي شيء مشترك بين A وB وC وD، فإن إضافة فئة أساسية لن تحصل على أي شيء حقًا.ستكون مجرد فئة فارغة وستكون في الواقع نفس الكائن.

أود فقط إنشاء فئة ErrorItem بدون الأدوية العامة، وجعل العنصر كائنًا وإجراء بعض عمليات الإرسال عندما تريد استخدام الكائنات المشار إليها.إذا كنت تريد استخدام أي من الخصائص أو الأساليب الخاصة بالفئة A أو B أو C أو D بخلاف الدليل، فسيتعين عليك إرسالها على أي حال.

نصائح أخرى

هل هذا ما كنت تبحث عنه؟

private List<ErrorItem<object>> _allObjects = new List<ErrorItem<object>>();

public IEnumerable<ErrorItem<A>> ItemsOfA
{
    get
    {
        foreach (ErrorItem<object> obj in _allObjects)
        {
            if (obj.Item is A)
                yield return new ErrorItem<A>((A)obj.Item, obj.MetaData);
        }
    }
}

إذا كنت تريد تخزين ذاكرة التخزين المؤقت ItemsOfA يمكنك القيام بذلك بسهولة:

private List<ErrorItem<A>> _itemsOfA = null;

public IEnumerable<ErrorItem<A>> ItemsOfACached
{
    if (_itemsOfA == null)
        _itemsOfA = new List<ErrorItem<A>>(ItemsOfA);
    return _itemsOfA;
}

الإجابة التي سأقدمها حتى الآن هي مزيج من الإجابات المقدمة من فرايجويبوب ومندلت سيبينجا.

إن إضافة فئة أساسية لن يؤدي إلا إلى تلويث مساحة الاسم وتقديم مشكلة مماثلة، كما أشار مندلت سيبينجا.سأحصل على مزيد من التحكم في العناصر التي يمكن إدخالها في المجموعة، ولكنني سأظل بحاجة إلى تخزينها ErrorItem<BaseClass> وما زلت أقوم ببعض عمليات الاختيار، لذلك سأواجه مشكلة مختلفة قليلاً لنفس السبب الجذري.لهذا السبب اخترت المنشور كإجابة:إنه يشير إلى أنني سأضطر إلى القيام ببعض الممثلين بغض النظر عن الأمر، وسوف تملي KISS أن الفئة الأساسية الإضافية والأدوية العامة أكثر من اللازم.

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

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