سؤال

في دلفي, IUnknown تم الإعلان عنه على أنه:

function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

ملاحظة: معلمة الإخراج غير مكتوبة

في بلدي TInterfacedObject سليل أحتاج إلى التعامل معها QueryInterface, ، حتى أتمكن من إرجاع كائن يدعم الواجهة المطلوبة:

function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
   if IsEqualGUID(IID, IFooBar) then
   begin
      Obj := (TFooBar.Create(Self) as IFooBar);
      Result := S_OK;
   end
   else
      Result := inherited QueryInterface(IID, {out}Obj);
end;

المشكلة تأتي على الخط:

Obj := (TFooBar.Create(Self) as IFooBar);

يشكو دلفي:

المشغل لا ينطبق على هذا النوع المعامل

من الواضح أنني لا أعرف كيف أو ماذا أسند إلى غير مكتوب out المعلمة.يمكنني تجربة الأشياء بشكل عشوائي ، على أمل أن يتوقف المترجم عن الشكوى:

Obj := TFooBar.Create(Self);

Obj := Pointer(TFooBar.Create(Self));

Obj := Pointer(TFooBar.Create(Self) as IFooBar);

تجاهل كل التعليمات البرمجية التي كتبتها (إذا لزم الأمر):كيف يمكنني تنفيذ QueryInterface في كائن سليل من TInterfacedObject?


المشكلة الحقيقية لقد كنت تحاول حل يمكن المغلي وصولا الى أريد أن:

أريد تجاوز الأساليب في واجهة

بنفس الطريقة:

TList = class(TObject)
...
   function GetItem(Index: Integer): Pointer; 
   procedure SetItem(Index: Integer; Value: Pointer);
   property Items[Index: Integer]: Pointer read GetItem write SetItem;
end;

يمكن تجاوزها في فئة سليل:

TStudentList = class(TList)
...
   function GetItem(Index: Integer): TStudent; 
   procedure SetItem(Index: Integer; Value: TStudent);
   property Items[Index: Integer]: TStudent read GetItem write SetItem;
end;

أريد أن نفس الشيء مع واجهات:

IFoo = interface(IUnknown)
...
   function GetItem(Index: Variant): Variant; 
   procedure SetItem(Index: Variant; Value: Variant);
   property Items[Index: Variant]: Variant read GetItem write SetItem;
end;

IFooGuidString = interface(IFoo)
...
   function GetItem(Index: TGUID): string ; 
   procedure SetItem(Index: TGUID; Value: string );
   property Items[Index: TGUID]: string read GetItem write SetItem;
end;

المشكلة هي كيف يجب أن أبدأ في تحميل كائن التنفيذ الخاص بي مع:

TFoo = class(TInterfacedObject, IFoo, IFooGuidString)
public
   function IFoo.GetItem = FooGetItem;
   procedure IFoo.SetItem = FooSetItem;
   function FooGetItem(Index: Variant): Variant; 
   procedure FooSetItem(Index: Variant; Value: Variant);

   function IFooGuidString.GetItem = FooGuidStringGetItem;
   procedure IFooGuidString.SetItem = FooGuidStringSetItem;
   function FooGuidStringGetItem(Index: TGUID): string ; 
   procedure FooGuidStringSetItem(Index: TGUID; Value: string );
end;

وليس هناك فقط طريقتين في IFoo, ، هناك 6.ثم إذا كنت ترغب في إضافة واجهة أخرى معتمدة:

IFooInt64String = interface(IFoo)
...
   function GetItem(Index: Int64): string ; 
   procedure SetItem(Index: Int64; Value: string );
   property Items[Index: Int64]: string read GetItem write SetItem;
end;


TFoo = class(TInterfacedObject, IFoo, IFooGuidString)
public
   function IFoo.GetItem = FooGetItem;
   procedure IFoo.SetItem = FooSetItem;
   function FooGetItem(Index: Variant): Variant; 
   procedure FooSetItem(Index: Variant; Value: Variant);

   function IFooGuidString.GetItem = FooGuidStringGetItem;
   procedure IFooGuidString.SetItem = FooGuidStringSetItem;
   function FooGuidStringGetItem(Index: TGUID): string ; 
   procedure FooGuidStringSetItem(Index: TGUID; Value: string );

   function IFooInt64String.GetItem = FooInt64StringGetItem;
   procedure IFooInt64String.SetItem = FooInt64StringSetItem;
   function FooInt64StringGetItem(Index: Int64): string ; 
   procedure FooInt64StringSetItem(Index: Int64; Value: string );
end;

وتصبح الأمور غير عملية حقا بسرعة كبيرة.

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

المحلول

تحتاج إلى كتابة-يلقي اليسار جانب بيان المهمة.بهذه الطريقة ، تحتوي المعلمة غير المكتوبة على نوع ، ويعرف المترجم كيفية تعيين قيمة لها:

IFooBar(Obj) := TFooBar.Create(Self) as IFooBar;

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

Foo.QueryInterface(IUnknown, I1);
I1.QueryInterface(IFooBar, B);
B.QueryInterface(IUnknown, I2);
Assert(I1 = I2);

إذا كنت ترغب فقط في إنشاء كائنات جديدة من نوع تفوبار ، ثم إعطاء واجهة الخاص بك طريقة التي تولد تلك:

function TFoo.NewFooBar: IFooBar;
begin
  Result := TFooBar.Create(Self) as IFooBar;
end;

نصائح أخرى

إلى جانب تصريحات روب بخرق القواعد هنا ، يمكنك حتى النجاح في هذا البناء:

function TFoo.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
   if IsEqualGUID(IID, IFooBar) then
      Result := TFooBar.Create(Self).QueryInterface(IID, obj)
   else
      Result := inherited QueryInterface(IID, {out}Obj);
end;

لم أكن التحقيق في هذا ، ولكن قد تحصل على بعض المشاكل مع العد المرجعي...

بناء على تنفيذ توبجيكت.الحصول على واجهة في النظام.با أود أن أقترح هذا:

  Pointer(Obj) := TFooBar.Create(Self);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top