في المقالة "Strong Delphi RTTI - مناقشة حول الحاجة إلى فهم لغات التطوير المتعددة" ، قلت إنني استخدمت RTTI من Delphi لتنفيذ عرض بسيط لمجموعات البيانات. ستقدم هذه المقالة طريقة التنفيذ الخاصة بي بالتفصيل.
لنبدأ بمثال بسيط: افترض أن هناك عنصر تحكم Adodataset يتصل بقاعدة بيانات Roswen ، و SQL هو:
حدد * من الموظف
أنت الآن بحاجة إلى عرض Four Fields EmployeeId و FirstName و LastName و Rity في محتواه في ListView. الرمز التقليدي هو كما يلي:
مع adodataset1 تبدأ في فتحها ؛ FieldByName (اسم العائلة).
هناك العديد من المشاكل الرئيسية هنا:
1. أولاً وقبل كل شيء ، هناك الكثير من الرموز التي تكون مطوّلة للغاية. على سبيل المثال ، FieldByName و ASXXX ، وما إلى ذلك ، وخاصة ASXXX ، يجب أن تتذكر دائمًا نوع كل حقل ، وهو أمر سهل ارتكاب أخطاء. علاوة على ذلك ، إذا كان لا يمكن تحويل بعض الأنواع غير المتوافقة تلقائيًا ، فلن يتم العثور على أخطاء حتى وقت التشغيل.
2. تحتاج إلى معالجة حركة السجل الحالية في الحلقة بنفسك. مثل التالي ، وإلا فإن الحلقة الميتة ستحدث بمجرد نسيانها.
3. أهم شيء هو أن اسم الحقل قد تم تمريره من خلال المعلمة السلسلة. FieldByName ، من المحتمل أن يظهر مثل هذه المشكلة فقط إذا تأخرت العميل. من السهل حدوث هذا النوع من أسماء الحقول الخاطئة ، خاصةً عندما يستخدم البرنامج جداول متعددة ، فمن السهل الخلط بين أسماء الحقول لجداول مختلفة.
في هذه الحقبة التي يحكمها OO ، عندما نواجه عمليات تتعلق بمجموعات البيانات ، لا يزال يتعين علينا أن نقع في كثير من الأحيان في تفاصيل قاعدة البيانات العلائقية المذكورة أعلاه. بالطبع ، هناك أيضًا طريقة للتخلص منها الآن ، أي رسم خرائط O/R ، لكن رسم الخرائط O/R يختلف كثيرًا عن طرق التطوير التقليدية بعد كل شيء ، وخاصة بالنسبة لبعض التطبيقات الصغيرة ، ليست هناك حاجة للمبالغة في هذه الحالة ، كل ما نحتاجه هو مخطط بيانات بيانات بسيط.
مستوحاة من Java واللغات الديناميكية الأخرى ، فكرت في استخدام RTTI القوي من Delphi لتنفيذ مخطط موضوعات مجموعة البيانات البسيطة. فيما يلي رمز تطبيق DataSet Objectified الذي ينفذ نفس الوظائف مثل الكود التقليدي:
اكتب TDSPEMPLIESE = فئة (TMDATASETPROXY) PORTREMENT EMPLORTED: PROTECTION SETINTEGER SetVariant ؛ (Emp.Employeid) ؛ Emp.Free نهاية.
الاستخدام بسيط للغاية. الشيء الأكثر أهمية هو تحديد فئة الوكيل أولاً ، والتي تستخدم السمة المنشورة لتحديد جميع الحقول ، بما في ذلك أنواعها ، ثم يمكنك معالجة مجموعة البيانات بطريقة كائن. يتم اشتقاق فئة الوكيل هذه من TMDATASETPROXY ، والتي تستخدم RTTI لتنفيذ التعيين من عمليات السمات إلى العمليات الميدانية. سيتم شرح وحدات تنفيذ هذه الفئة بالتفصيل أدناه.
على السطح ، هناك فئة وكيل إضافية تحدد مجموعة البيانات ، والتي يبدو أن لديها المزيد من التعليمات البرمجية ، ولكن هذا شيء لمرة واحدة ، خاصة عندما يحتاج البرنامج إلى إعادة استخدام نفس بنية مجموعات البيانات عدة مرات ، الرمز سيتم تصنيعها. والأكثر من ذلك ، أن تعريف فئة الوكيل هذا بسيط للغاية. يتم تنفيذ وظائف الوصول إلى السمة getxxx/setxxx المستخدمة جميعها في الفئة الأساسية tmdatasetproxy.
الآن دعونا نلقي نظرة على الحلقة المقابلة للرمز الأصلي:
1. FieldByName و ASXXX غير مطلوبة ، وأصبحت عمليات سمة على فصول الوكيل. من. إذا تم استخدام النوع الخطأ ، فسيتم الإبلاغ عن خطأ أثناء التجميع.
2. استخدم foreach لأداء اجتياز التسجيلات ، ولم يعد داعي للقلق بشأن نسيان الحلقة المفرغة الناجمة عن التالي.
3. أكبر ميزة هي أن اسم الحقل يصبح خاصية ، حتى تتمكن من الاستمتاع بمزايا التحقق من اسم الحقل في وقت الترجمة.
ابدأ الآن في مناقشة tmdatasetproxy. مدونة تنفيذها على النحو التالي:
(*************************************************** ****** المستخدمالتاريخ: يناير 28-05 ****************************************** ******** المستخدم (Aindex: integer) Propers [inteex]: وظيفة الإجراءات الافتراضية ؛ : Tdataset) ClassInfo)^ (FPROPLIST) tmproplist.getPropName (anIndex: integer): StringString ؛ ابدأ النتيجة: = getProp (Aindex) ; FLooping := false;end;destructor TMDataSetProxy.Destroy; begin FPropList.Free; If Assigned( FDataSet ) Then FDataSet.Close; inherited; end;procedure TMDataSetProxy.AfterConstruction; began inherited; FPropList := TMPropList.Create( Self ); END ؛ الإجراء TMDATASETPROXY.BEGINEDIT .state = dsinsert) : integer): double ؛ ابدأ النتيجة: = fdataset.fieldbyname (fproplist.propnames [aindex]) .Asfloat ؛ end ؛ وظيفة tmdatasetproxy.getString (anIndex: integer): String ؛ string ؛ Aindex]) .AssTring ؛ end ؛ وظيفة tmdataseTproxy.getVariant (Aindex: integer): variant ؛ ابدأ النتيجة: = fdataset.fieldbyname (fproplist.propnames [aindex]) .value ؛ end ؛ incdure tmdatasetproxy.setinteinte (aindex ، avalue: inteex ، ) ] Aindex: integer ابتداء عن ذلك.
فئة TMPROPlist هي تغليف لبعض وظائف عملية سمة RTTI. تتمثل وظيفتها في استخدام بعض وظائف RTTI المحددة بواسطة Delphi في وحدة TypInfo لتنفيذ فئة مشتقة من tpersenteration للحفاظ على معلومات قائمة الممتلكات المنشورة. تحصل فئة الوكيل على اسم السمة من خلال قائمة السمات هذه ، وأخيراً تعمل من خلال اسم السمة هذا والحقول المقابلة في مجموعة البيانات.
TMDATASETPROXY هي الفئة الأساسية لفئة وكيل مجموعة البيانات. الجزء الأكثر أهمية هو إنشاء قائمة خصائص في البناء اللاحق.
يقوم تشغيل السمات بتنفيذ أربعة أنواع بيانات فقط: عدد صحيح ، مزدوج/تعويم ، سلسلة ، ومتغير. إذا لزم الأمر ، يمكنك استخلاص فئة قاعدة الوكيل الخاصة بك على هذا الأساس لتنفيذ أنواع البيانات الأخرى. تنفيذ استبداله. ومع ذلك ، بالنسبة للأنواع غير المستخدمة بشكل شائع ، يوصى بتحديد فئة الوكيل الفعلية قبل تنفيذها. على سبيل المثال ، في المثال السابق ، على افتراض أن tdatetime ليس نوعًا شائع الاستخدام ، يمكنك القيام بذلك:
TDSPEMPLOYE = فئة (TMDATASETPROXY) قراءة PROPENTIONAL LAGHTRING GETSTRING ؛ (GetVariant (INDEX) ؛ End ؛ Procedure TDSPEMPLISTER.
وبهذه الطريقة ، يمكنك استخدام تاريخ الميلاد مباشرة كنوع TDATETEM.
بالإضافة إلى ذلك ، الاستفادة من ذلك ، من الممكن توفير عمليات موحدة لبعض أنواع البيانات الخاصة المخصصة.
أيضًا ، تم استدعاء LeGinedit قبل جميع setxxx لتجنب أخطاء وقت التشغيل الناتجة عن نسيان استخدام مجموعة البيانات.
يتم تنفيذ Foreach ليكون قابلاً لإعادة الاستخدام. بالإضافة إلى ذلك ، يتم استدعاء Endedit من قبل بجوار إرسال التغييرات تلقائيًا.
يعد مخطط مجموعة البيانات هذا حلًا بسيطًا للغاية. هذا لأن Delphi لا تزال لغة تطوير محلية بعد كل شيء. لا ديناميكية ، لذلك يمكنك فقط استخدام الطريقة الحالية للتسجيل.