التجريد يعيق استخدام الأنواع المخصصة ، ما هي القواعد التي يجب اتباعها في التنفيذ؟

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

سؤال

لقد قمت ببناء نظام أنواع مخصص للاستخدام في C# البرمجة النصية داخل التطبيق. يتم تجميع البرامج النصية أثناء التنقل وتسمح بالتفاعل مع البيانات الداخلية للتطبيق. تم تصميم هذا الأنواع بطريقة مجردة باستخدام واجهات مثل IValue. بداية شئ IValue يمكن أن يكون RefString, RefInteger, RefDouble (من بين أشياء أخرى كثيرة ، ولكن هذا يكفي لإظهار مشكلتي).

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

مثال:

IValue Add(IValue a, IValue b)
{
    //return a+b; // won't work: which operator +() to use?
    return (RefInteger)a + (RefInteger)b;
}

في حالة C# في التعبيرات التي تنطوي على أنواع القيمة ، يتم توفير تحويلات ضمنية. ما هي الطريقة الجيدة لتصميم مثل هذا النظام المخصص؟

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

تعديل: بعد النضال لفترة من الوقت ، بعض القواعد التي يمكنني اكتشافها هي:

  • إعلان ضمنيًا فقط مشغلي التحويل من الأنواع الأساسية (int ، مزدوجة ، سلسلة ، ...)
  • أعلن صريحًا التحويلات إلى الأنواع الأساسية (لتجنب القوالب الضمنية إلى int !! ماذا يحدث في كثير من الأحيان ، ولكن لماذا؟)
  • لتجنب المكالمات الغامضة ، لا ينبغي تجاوز المشغلين +، /، * في الفئة الأساسية وفي الفئات المشتقة. [ما هي السبيل للذهاب بعد ذلك؟ لقد قمت بالعملية الزائدة في الفصول المشتقة ، وهذا يتطلب الاستخدام ، وهو قبيح مرة أخرى ...
هل كانت مفيدة؟

المحلول

إذا كان من المفترض أن تكون قادرًا على عمل Add العملية على الجميع IValueS ، ربما يجب أن تشمل الواجهة Add طريقة؟ ثم يمكنك أن تفعل return a.Add(b);, ، وادفع معرفة كيفية أداء العملية في كل نوع.

مشكلة واحدة هي أنه كما يبدو الآن ، يمكنك الحصول على مكالمات حيث a هو RefString و b هو RefInteger, ، ربما ليس ما تريد. يمكن أن تساعد الأدوية في إصلاح ذلك:

T Add<T>(T a, T b) where T : IValue
{
    return a.Add(b);
}

(بالطبع ستحتاج إلى إضافة فحص فارغ ومثل)

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