Reputation: 183
I´m facing a problem between Delphi 2010 and Delphi Berlin (last update) during my code migration.... I made a simple code to demonstrante an strange behaviour...
I have an application that use TList (the former one) and TList (from Generics.Collections) I know that this piece of code (below) doesn´t make any sense for you, but it´s for demonstration purposes
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.
At Delphi 2010 the ShowMessage shows 'A' character, but on the Delphi Berlin it raises an Acess Violation
Both applications with Optimization set to False
Upvotes: 5
Views: 189
Reputation: 612794
FList := TList(tmpList);
This is the problem. The cast is simply wrong, because tmpList
is not a TList
.
Your code only compiles because of the cast, but the cast does not change the fact that the object on the right hand side is not of the type being casted to. All the cast does is stop the compiler from complaining and saving you from yourself. Your cast is a lie to the compiler, and the runtime error is the consequence.
This code might have worked in older versions, but only by chance. Your luck has changed.
Hard to know what to suggest for a fix. As you say, the code makes little sense. Every time you press the button, you leak a list. I'd suggest that you remove all the casts, stop using the non-Generic TList
and use only Generic lists.
Upvotes: 9
Reputation: 23036
The class TList<T>
is not castable to/from TList
.
You cannot cast one to the other and expect sensible results any more than you could cast a TForm
to TButton
(for example).
In Delphi, typecasts of this form are unchecked, sometimes referred to as hard-casting. That is, the compiler will simply trust that you know what you are doing and will simply comply, but if the typecast is invalid then the results will be unpredictable.
For conversions between object reference types (and/or interface references) you can use a checked cast using the as operator:
FList := tmpList as TList;
If a checked cast is invalid (such as this one is) then the compiler will throw a runtime exception, alerting you to the mistake.
In some cases unchecked casting can be useful and safely relied upon, within specific use cases. But outside of those specific conditions unchecked casts are at best trusting to luck or on specific compiler behaviours or RTL characteristics which may be subject to change.
e.g. the 32-bit trick of storing object references or other pointer values in an Integer variable. Such code may continue to work when recompiled for 64-bit, but now only as a matter of luck and only in some cases, since only a subset of possible 64-bit pointer values can safely be stored in a 32-bit Integer.
If you have code which is successfully hard-casting between TList
and TList<T>
then it worked only by luck, as a result of some particular behaviour of the compiler or RTL at that time.
Upvotes: 6