سؤال

بالنظر إلى سلسلة نصية تحتوي على اسم نوع، هل هناك طريقة للحصول على النوع المناسب نفسه؟

أنا أتطلع إلى القيام بشيء مثل هذا:

type
  TSomeType<T> = class
    // yadda yadda
  end;

procedure DoSomething;
var
  obj : TObject;
begin
  o := TSomeType<GetTypeByName('integer')>.Create;
  // do stuff with obj
end;

لقد بحثت في العديد من التفسيرات RTTI عبر الإنترنت ونظرت من خلال وحدات Delphi ولا ترى ما أبحث عنه. هل هذا ممكن؟

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

المحلول

لا، الجنراء مجمعة تماما.

نصائح أخرى

تتمتع وحدة RTTI الجديدة في Delphi 2010 بأي طريقة لاسترجاع الأنواع المعلنة في قسم الواجهة من الوحدات. لأي نوع معين، يمثله TRttiType المثال، TRttiType.QualifiedName إرجاع العقار اسما يمكن استخدامه TRttiContext.FindType في وقت لاحق لاسترداد النوع. الاسم المؤهل هو اسم الوحدة الكاملة (بما في ذلك مساحات الأسماء، إذا كانت موجودة)، متبوعة ب "."، تليها اسم النوع الكامل (بما في ذلك الأنواع الخارجية إذا كانت متداخلة).

لذلك، يمكنك استرداد تمثيل للنوع الصحيحة (في شكل TRttiType) مع context.FindType('System.Integer').

لكن هذه الآلية لا يمكن استخدامها لاسترداد إنشاء إنشاءات من الأنواع العامة التي لم يتم إنشاء مثيل لها في وقت الترجمة؛ إن إنشاء مثيل في وقت التشغيل يتطلب جيل رمز وقت التشغيل.

يمكنك دائما تسجيل أنواعك في نوع من السجل (تدار بواسطة قائمة أو قاموس سلسلة) وإنشاء وظيفة المصنع ثم إرجاع الكائن المناسب. لسوء الحظ، عليك أن تعرف مقدما من أنواع التي ستحتاجها. شيء مشابه ل Delphi وظائف تسجيل و FindClass (في وحدة الطبقات). تفكيري هو وضع نوع القالب عام في القائمة مباشرة.

مثال على الاستخدام المحتمل:

RegisterCustomType('Integer',TSomeType<Integer>);
RegisterCustomType('String',TSomeType<String>);

if FindCustomType('Integer') <> nil then
  O := FindCustomType('Integer').Create;

تعديل: فيما يلي تطبيق بسيط محدد باستخدام TDICTIONARY من Generics.collections للتعامل مع مساحة التسجيل ... سأترك استخراج هذا إلى أساليب مفيدة كممارسة بسيطة للقارئ.

var
  o : TObject;
begin
  TypeDict := TDictionary<String,TClass>.Create;
  TypeDict.Add('integer',TList<integer>);
  if TypeDict.ContainsKey('integer') then
    o := TypeDict.Items['integer'].Create;
  if Assigned(o) then
    ShowMessage(o.ClassName);
end;

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

TYPE
  ITest = interface
    ['{0DD03794-6713-47A0-BBE5-58F4719F494E}']
  end;

  TIntfList<t> = class(TList<T>,ITest)
  public
    function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;

procedure TForm1.Button7Click(Sender: TObject);
var
  o : TObject;
  fTestIntf : ITest;
begin
  TypeDict := TDictionary<String,TClass>.Create;
  TypeDict.Add('integer',TIntfList<integer>);
  if TypeDict.ContainsKey('integer') then
    o := TypeDict.Items['integer'].Create;
  if Assigned(o) and Supports(o,ITest,fTestIntf) then
    ShowMessage(o.ClassName);
end;

بالطبع، يجب عليك تطبيق أساليب QueryInterface، _ADDREF و _Release وتوسيع الواجهة للقيام بشيء أكثر فائدة.

إذا نسيت الأجهزة والأنواع الأساسية، فستكون وظيفة "RegisterClass" مفيدة. لكنها لا تعمل على الأجهزة أو الأنواع الأساسية.

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