将实现子接口的对象作为其父接口参数传递
Passing object which implements a child interface as its parent interface parameter
我有一个父接口 (IParent
)、一个子接口 (IChild
) 和一个实现子接口的对象。
我正在尝试通过传递实现子接口的对象数组来调用接受 array of IParent
参数的函数。
编译时出现以下错误:
[dcc32 Error] Unit1.pas(46): E2010 Incompatible types: 'IParent' and
'TForm1'
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
type
IParent = interface
procedure DoSomething();
end;
IChild = interface(IParent)
procedure DoSomethingElse();
end;
TForm1 = class(TForm, IChild)
procedure FormCreate(Sender: TObject);
public
procedure DoSomething();
procedure DoSomethingElse();
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure CallAllDoSomething(AArray : array of IParent);
var
i : integer;
begin
i := 0;
while(i < Length(AArray)) do
begin
AArray[i].DoSomething();
Inc(i);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Unit1.CallAllDoSomething([Self]);
end;
procedure TForm1.DoSomething();
begin
ShowMessage('Something');
end;
procedure TForm1.DoSomethingElse();
begin
ShowMessage('Something else');
end;
end.
您必须将 IParent
添加到 TForm1
的声明中,以便:
TForm1 = class(TForm, IParent, IChild)
为了将 TForm1
对象 直接 分配给 IParent
,您必须在 TForm1
中包含 IParent
的声明:
TForm1 = class(TForm, IParent, IChild)
Embarcadero 的 DocWiki 中记录了此行为:
Implementing Interface References
An interface-type expression cannot reference an object whose class implements a descendent interface, unless the class (or one that it inherits from) explicitly implements the ancestor interface as well.
For example:
type
IAncestor = interface
end;
IDescendant = interface(IAncestor)
procedure P1;
end;
TSomething = class(TInterfacedObject, IDescendant)
procedure P1;
procedure P2;
end;
// ...
var
D: IDescendant;
A: IAncestor;
begin
D := TSomething.Create; // works!
A := TSomething.Create; // error
D.P1; // works!
D.P2; // error
end;
In this example, A is declared as a variable of type IAncestor. Because TSomething does not list IAncestor among the interfaces it implements, a TSomething instance cannot be assigned to A. But if you changed TSomething's declaration to:
TSomething = class(TInterfacedObject, IAncestor, IDescendant)
// ...
the first error would become a valid assignment. D is declared as a variable of type IDescendant. While D references an instance of TSomething, you cannot use it to access TSomething's P2 method, since P2 is not a method of IDescendant. But if you changed D's declaration to:
D: TSomething;
the second error would become a valid method call.
或者,由于 IChild
派生自 IParent
,您可以先 显式 将 TForm1
对象转换为 IChild
,然后让编译器为您将 IChild
转换为 IParent
:
Unit1.CallAllDoSomething([IChild(Self)]);
此行为也记录在案:
Interface Assignment Compatibility
Variables of a given class type are assignment-compatible with any interface type implemented by the class. Variables of an interface type are assignment-compatible with any ancestor interface type. The value nil
can be assigned to any interface-type variable.
我有一个父接口 (IParent
)、一个子接口 (IChild
) 和一个实现子接口的对象。
我正在尝试通过传递实现子接口的对象数组来调用接受 array of IParent
参数的函数。
编译时出现以下错误:
[dcc32 Error] Unit1.pas(46): E2010 Incompatible types: 'IParent' and 'TForm1'
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
type
IParent = interface
procedure DoSomething();
end;
IChild = interface(IParent)
procedure DoSomethingElse();
end;
TForm1 = class(TForm, IChild)
procedure FormCreate(Sender: TObject);
public
procedure DoSomething();
procedure DoSomethingElse();
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure CallAllDoSomething(AArray : array of IParent);
var
i : integer;
begin
i := 0;
while(i < Length(AArray)) do
begin
AArray[i].DoSomething();
Inc(i);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Unit1.CallAllDoSomething([Self]);
end;
procedure TForm1.DoSomething();
begin
ShowMessage('Something');
end;
procedure TForm1.DoSomethingElse();
begin
ShowMessage('Something else');
end;
end.
您必须将 IParent
添加到 TForm1
的声明中,以便:
TForm1 = class(TForm, IParent, IChild)
为了将 TForm1
对象 直接 分配给 IParent
,您必须在 TForm1
中包含 IParent
的声明:
TForm1 = class(TForm, IParent, IChild)
Embarcadero 的 DocWiki 中记录了此行为:
Implementing Interface References
An interface-type expression cannot reference an object whose class implements a descendent interface, unless the class (or one that it inherits from) explicitly implements the ancestor interface as well.
For example:
type IAncestor = interface end; IDescendant = interface(IAncestor) procedure P1; end; TSomething = class(TInterfacedObject, IDescendant) procedure P1; procedure P2; end; // ... var D: IDescendant; A: IAncestor; begin D := TSomething.Create; // works! A := TSomething.Create; // error D.P1; // works! D.P2; // error end;
In this example, A is declared as a variable of type IAncestor. Because TSomething does not list IAncestor among the interfaces it implements, a TSomething instance cannot be assigned to A. But if you changed TSomething's declaration to:
TSomething = class(TInterfacedObject, IAncestor, IDescendant) // ...
the first error would become a valid assignment. D is declared as a variable of type IDescendant. While D references an instance of TSomething, you cannot use it to access TSomething's P2 method, since P2 is not a method of IDescendant. But if you changed D's declaration to:
D: TSomething;
the second error would become a valid method call.
或者,由于 IChild
派生自 IParent
,您可以先 显式 将 TForm1
对象转换为 IChild
,然后让编译器为您将 IChild
转换为 IParent
:
Unit1.CallAllDoSomething([IChild(Self)]);
此行为也记录在案:
Interface Assignment Compatibility
Variables of a given class type are assignment-compatible with any interface type implemented by the class. Variables of an interface type are assignment-compatible with any ancestor interface type. The value
nil
can be assigned to any interface-type variable.