Delphi代码迁移问题

时间:2017-07-19 18:26:07

标签: delphi

我在代码迁移期间遇到了Delphi 2010和Delphi Berlin(上次更新)之间的问题.... 我做了一个简单的代码来证明一个奇怪的行为...

我有一个使用TList(前一个)和TList(来自Generics.Collections)的应用程序 我知道这段代码(下面)对你没有任何意义,但它是出于演示目的

unit Unit1;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
  TTest = class
    Name: string;
    constructor Create(Nome: string);
  end;
  TForm1 = class(TForm)
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FList: TList;
  end;
var
  Form1: TForm1;
implementation
uses
  System.Generics.Collections;
{$R *.dfm}

procedure TForm1.btn1Click(Sender: TObject);
var
  tmpList: TList<TTest>;
begin
  tmpList := TList<TTest>.Create;
  tmpList.Add(TTest.Create('A'));
  tmpList.Add(TTest.Create('B'));
  tmpList.Add(TTest.Create('C'));
  tmpList.Add(TTest.Create('D'));
  tmpList.Add(TTest.Create('E'));
  FList := TList(tmpList);
  ShowMessage(TTest(FList[0]).Name);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FList := TList.Create;
end;

constructor TTest.Create(Nome: string);
begin
  Name := Nome;
end;
end.

在Delphi 2010中,ShowMessage显示'A'字符,但在Delphi Berlin上它会引发Acess Violation

优化的两个应用程序都设置为False

2 个答案:

答案 0 :(得分:9)

FList := TList(tmpList);

这就是问题所在。演员阵容完全错误,因为tmpList不是TList

您的代码仅因为强制转换而编译,但强制转换不会改变右侧对象不属于要转换的类型的事实。所有演员都会阻止编译器抱怨并将你从自己身上拯救出来。你的演员阵容是编译器的谎言,结果是运行时错误。

此代码可能适用于旧版本,但只是偶然。你的运气发生了变化。

很难知道修复建议的内容。正如你所说,代码没有多大意义。每次按下按钮,都会泄漏列表。我建议您删除所有演员表,停止使用非Generic TList并仅使用Generic列表。

答案 1 :(得分:6)

课程TList<T>不能投放到TList

你不能将一个投射到另一个并且期望得到明显的结果,而不是将TForm投射到TButton(例如)。

在Delphi中,此表单的类型转换未经检查,有时称为 hard-casting 。也就是说,编译器只会相信您知道自己在做什么并且只是遵守,但如果类型转换无效,那么结果将是不可预测的。

对于对象引用类型(和/或接口引用)之间的转换,您可以使用作为运算符使用已检查强制转换:

FList := tmpList as TList;

如果选中的强制转换无效(例如这个),则编译器将抛出运行时异常,提醒您错误。

为什么编译器甚至允许未经检查的强制转换?

在某些情况下,在特定用例中,未经检查的铸造可能是有用且安全的依赖。但是在这些特定条件之外,未经检查的强制转换最多只能信赖运气或特定的编译器行为或RTL特性,这些特性可能会发生变化。

e.g。在 Integer 变量中存储对象引用或其他指针值的32位技巧。这样的代码可能在重新编译为64位时继续工作,但现在只是为了运气而且仅在某些情况下,因为只有一部分可能的64位指针值可以安全地存储在一个32位的整数。

如果您的代码在TListTList<T>之间成功地进行了强制转换,那么由于当时编译器或RTL的某些特定行为,它只能运气好。