gpt4 book ai didi

delphi - 为接口(interface)引入附加名称时,从接口(interface)转换到类失败 - 为什么?

转载 作者:行者123 更新时间:2023-12-03 18:51:33 25 4
gpt4 key购买 nike

我偶然发现了在某些情况下从接口(interface)到类的硬转换失败的情况。

考虑以下类型定义:

  IDummy<T> = interface
end;
TMyRecord = record
Intf:IDummy<Byte>;
end;
TDummy = class(TInterfacedObject, IDummy<Byte>)
public
end;

IThisBreaksIt = IDummy<Byte>; // <== this line triggers the error

现在使用这些类型的简单代码:
var
ARecord:TMyRecord;
Item:IDummy<Byte>;

ImplWorks,
ImplBroken:TDummy;
begin
ARecord.Intf:=TDummy.Create;
Item:=ARecord.Intf;

ImplWorks:=TDummy(Item);
ImplBroken:=TDummy(ARecord.Intf); // <== resulting instance is broken
end;

所以我正在做的是将接口(interface)引用存储在记录中。现在我想通过硬转换将其转换回实现类。

这是一个问题:如果我为我的接口(interface)定义别名( IThisBreaksIt = IDummy<Byte> ),这将失败。注释掉这一行和 ImplBroken不再 splinter 。在损坏的情况下, ImplWorks 的地址和 ImplBroken是不同的;而是 Item 的地址和 ImplBroken现在是一样的。似乎负责硬类型转换的自动魔法无法发挥作用。

其他发现:替换 TDummy(ARecord.Intf)通过 ARecord.Intf as TDummy修复它。

这让我有些头疼,因为它被埋在一堆代码中,我没想到会出现这种行为。这是正常的吗?

编辑 Cosmin :

努力将接口(interface)转换为对象的示例。

在 XE 中测试:有效(StreamAdaptIntf 和 StreamAdaptImpl 的指针不同;断言成功)
2009年测试:失败(StreamAdaptIntf和StreamAdaptImpl的指针相同;Assertion失败)
uses ActiveX;

var
Stream:TStream;
StreamAdaptIntf:IStream;
StreamAdaptImpl:TStreamAdapter;
begin
Stream:=TMemoryStream.Create;
StreamAdaptIntf:=TStreamAdapter.Create(Stream, soOwned);

StreamAdaptImpl:=TStreamAdapter(StreamAdaptIntf);
Assert(Integer(StreamAdaptImpl) <> Integer(StreamAdaptIntf));
end;

最佳答案

可能没有帮助,这个问题是很久以前提出的,但是对于将来检查这个问题的任何人......

您可能刚刚发布了测试代码,但您的界面应该包含一个 GUID,该 GUID 唯一地定义了编译器的界面(在 Delphi 2009 中为 Ctrl+Shift+G)。

IDummy<T> = interface
['{F9EF740B-FF23-465A-A2E0-E2ACD5ABD90F}']
procedure DoSomething;
end;

硬类型转换通常是不安全的。只有在您知道对象类型正确的情况下,才能真正接受硬转换。类型转换时最好在类型转换之前检查其类型,如下所示......
var
lTypeA: TTypeA;
begin
if ObjectA is TTypeA then begin
lTypeA := TTypeA(ObjectA);
end;

更好的是,我会执行“as”强制转换,我认为如果它无效会导致异常。这真的更可取!我编写了执行硬转换的代码,只是为了花费数小时和数小时来弄清楚我的转换实际上是错误的...... Delphi 不会告诉你是否转换为错误的类型,然后当你以后使用该对象时,你最终会在整个调试的噩梦中。 as 将引发异常并引导您解决代码中的问题
var
lTypeA: TTypeA;
begin
if ObjectA is TTypeA then begin
// Will raise an exception if ObjectA is not TTypeA,
// in this simple case the ObjectA is TTypeA test is redundant
lTypeA := ObjectA as TTypeA;
end;

我真的只会在delphi中的对象之间进行转换。 Delphi 有一个有用的函数“支持”,它将确定一个对象是否实现了一个接口(interface),并返回一个该接口(interface)的实例。然后,您可以使用返回的局部变量从界面执行您需要的任何功能
if Supports(ImplBroken, IThisBreaksIt, lObjInterface) then
begin
lObjInterface.DoSomething;
end;

完整的代码...
type
// Generic IDummy interface
IDummy<T> = interface
['{F9EF740B-FF23-465A-A2E0-E2ACD5ABD90F}']
procedure DoSomething;
end;

// Don't alias interfaces if possible
// This is a more specific version of your interface
IThisBreaksIt = interface(IDummy<Byte>)
['{76EFA371-4674-4190-8A4B-06850103C1D8}']
end;

TMyRecord = record
// I would suggest, if you can avoid it don't store interfaces
// in a record, just simple types - just my opinion, delphi doesn't stop you
Intf: IDummy<Byte>;
end;

// Remember this is interfaced, so the object only exists while refcount > 0
TDummy = class(TInterfacedObject, IDummy<Byte>)
protected
{ IDummy<T> }
// interface methods should be protected
// So ideally we refer to the interface of this object,
// not publicly available methods
procedure DoSomething;
public
end;


var
ARecord: TMyRecord;
Item: IDummy<Byte>; // Think this should be IThisBreaksIt

ImplWorks:TDummy;
ImplBroken: IThisBreaksIt;
lObjInterface: IThisBreaksIt;
begin
ARecord.Intf := TDummy.Create;
Item := ARecord.Intf;

// Nasty hard cast here - what if your interfaced object is destroyed
// before you reach this code section?
ImplWorks := TDummy(Item);

// This line compiles, buts it's really not the right way to get the interface
ImplBroken := IThisBreaksIt(ARecord.Intf);

// I believe this is the right way to get the interface for an object
if Supports(ARecord.Intf, IThisBreaksIt, lObjInterface) then
begin
lObjInterface.DoSomething;
end;
end;

关于delphi - 为接口(interface)引入附加名称时,从接口(interface)转换到类失败 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5946719/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com