Problems with RTTI
I wrote an RTTI for TField a few weeks ago so I could get my field objects
at the beginning of the report instead of using the Pipeline['fieldName']
syntax (which is slow at runtime). I exposed the IsNull and AsString
properties of TField. Everything went fine and I've been using this in
production.
Today I wanted to add AsDateTime. I added it and found that it was always
returning Now instead of the TDateTime in the field object. So I started
debugging. My debugging revealed very strange behavior that I need help
with.
First, I found that my TRAPTFieldRTTI.GetPropValue function never gets
called. I put a breakpoint in it, but it never breaks. I thought, "How
odd." So I changed the name of my AsString method to "Foo".
TRAPTFieldRTTI.GetPropValue still never gets called and, not surprisingly,
my Foo property always evaluates to empty string.
I've boiled this down in a simple Delphi project which can be downloaded
from here:
http://msedd.com/bug.zip
My RTTI code looks like this:
---------------------------
const
AsStringStr='AsString';
{ TRAPTFieldRTTI }
TRAPTFieldRTTI = class(TraTComponentRTTI)
public
class procedure GetPropList(aClass: TClass; aPropList: TraPropList);
override;
class function GetPropRec(aClass: TClass; const aPropName: string; var
aPropRec: TraPropRec): boolean; override;
class function GetPropValue(aObject: TObject; const aPropName: string;
var aValue): boolean; override;
class function RefClass: TClass; override;
class function SetPropValue(aObject: TObject; const aPropName: string;
var aValue): boolean; override;
end;
class procedure TRAPTFieldRTTI.GetPropList( aClass: TClass;
aPropList: TraPropList);
begin
inherited GetPropList(aClass, aPropList);
aPropList.AddProp(AsStringStr);
end;
class function TRAPTFieldRTTI.GetPropRec(
aClass: TClass; const aPropName: string;
var aPropRec: TraPropRec): boolean;
begin
result:=true;
if ppEqual(aPropName, AsStringStr) then
PropToRec(aPropName, daString, false, aPropRec)
else result:=inherited GetPropRec(aClass, aPropName, aPropRec)
end;
class function TRAPTFieldRTTI.GetPropValue(
aObject: TObject; const aPropName: string; var aValue): boolean;
begin
result:=true;
if ppEqual(aPropName, AsStringStr) then
string(aValue):=TField(aObject).AsString
else result:=inherited GetPropValue(aObject, aPropName, aValue)
end;
class function TRAPTFieldRTTI.RefClass: TClass;
begin
result:=TField
end;
class function TRAPTFieldRTTI.SetPropValue(
aObject: TObject; const aPropName: string; var aValue): boolean;
begin
result:=true;
if ppEqual(aPropName, AsStringStr) then
TField(aObject).AsString:=string(aValue)
else result:=inherited SetPropValue(aObject, aPropName, aValue)
end;
initialization
raRegisterRTTI(TRAPTFieldRTTI);
finalization
raUnregisterRTTI(TRAPTFieldRTTI);
---------------------
My report contains a label with this RAP OnGetText handler:
var
blah: TField;
begin
blah:=DBPipeline1.FieldObjects['GenDate'];
Text := blah.AsString
end;
And yet, GetPropValue never executes. If you simply change the const
AsStringStr to "Foo" and then change the RAP to read "Text := blah.Foo",
you'll (hopefully) see that Foo always evaluates to empty string and
GetPropValue still never runs.
What's up? Am I missing something fundamental here?
Thanks,
Kevin Donn
at the beginning of the report instead of using the Pipeline['fieldName']
syntax (which is slow at runtime). I exposed the IsNull and AsString
properties of TField. Everything went fine and I've been using this in
production.
Today I wanted to add AsDateTime. I added it and found that it was always
returning Now instead of the TDateTime in the field object. So I started
debugging. My debugging revealed very strange behavior that I need help
with.
First, I found that my TRAPTFieldRTTI.GetPropValue function never gets
called. I put a breakpoint in it, but it never breaks. I thought, "How
odd." So I changed the name of my AsString method to "Foo".
TRAPTFieldRTTI.GetPropValue still never gets called and, not surprisingly,
my Foo property always evaluates to empty string.
I've boiled this down in a simple Delphi project which can be downloaded
from here:
http://msedd.com/bug.zip
My RTTI code looks like this:
---------------------------
const
AsStringStr='AsString';
{ TRAPTFieldRTTI }
TRAPTFieldRTTI = class(TraTComponentRTTI)
public
class procedure GetPropList(aClass: TClass; aPropList: TraPropList);
override;
class function GetPropRec(aClass: TClass; const aPropName: string; var
aPropRec: TraPropRec): boolean; override;
class function GetPropValue(aObject: TObject; const aPropName: string;
var aValue): boolean; override;
class function RefClass: TClass; override;
class function SetPropValue(aObject: TObject; const aPropName: string;
var aValue): boolean; override;
end;
class procedure TRAPTFieldRTTI.GetPropList( aClass: TClass;
aPropList: TraPropList);
begin
inherited GetPropList(aClass, aPropList);
aPropList.AddProp(AsStringStr);
end;
class function TRAPTFieldRTTI.GetPropRec(
aClass: TClass; const aPropName: string;
var aPropRec: TraPropRec): boolean;
begin
result:=true;
if ppEqual(aPropName, AsStringStr) then
PropToRec(aPropName, daString, false, aPropRec)
else result:=inherited GetPropRec(aClass, aPropName, aPropRec)
end;
class function TRAPTFieldRTTI.GetPropValue(
aObject: TObject; const aPropName: string; var aValue): boolean;
begin
result:=true;
if ppEqual(aPropName, AsStringStr) then
string(aValue):=TField(aObject).AsString
else result:=inherited GetPropValue(aObject, aPropName, aValue)
end;
class function TRAPTFieldRTTI.RefClass: TClass;
begin
result:=TField
end;
class function TRAPTFieldRTTI.SetPropValue(
aObject: TObject; const aPropName: string; var aValue): boolean;
begin
result:=true;
if ppEqual(aPropName, AsStringStr) then
TField(aObject).AsString:=string(aValue)
else result:=inherited SetPropValue(aObject, aPropName, aValue)
end;
initialization
raRegisterRTTI(TRAPTFieldRTTI);
finalization
raUnregisterRTTI(TRAPTFieldRTTI);
---------------------
My report contains a label with this RAP OnGetText handler:
var
blah: TField;
begin
blah:=DBPipeline1.FieldObjects['GenDate'];
Text := blah.AsString
end;
And yet, GetPropValue never executes. If you simply change the const
AsStringStr to "Foo" and then change the RAP to read "Text := blah.Foo",
you'll (hopefully) see that Foo always evaluates to empty string and
GetPropValue still never runs.
What's up? Am I missing something fundamental here?
Thanks,
Kevin Donn
This discussion has been closed.
Comments
begin
result:=TField
end;
result := TppField;
Likely it...
Tom Ollar
Digital Metaphors Corporation
P.S.
Great work utilizing RTTI
http://www.digital-metaphors.com
info@digital-metaphors.com
available at:
http://msedd.com/bug.zip
And did the following:
1) Changed the RefClass to TppField (which requires using ppDB).
2) Changed cast to TField in GetPropValue to TppField.
3) Removed SetPropValue entirely because TppField.AsString is read only and
changed the ReadOnly flag in PropToRec to true.
4) Change the RAP declaration to "blah: TppField."
Compiling this produces exactly the same result that it did before.
GetPropValue still doesn't execute. But now GetPropRec also doesn't run.
Since GetPropRec no longer runs, I can't add any new properties:
1) Change const definition of AsStringStr to 'Foo'.
2) Change the RAP to read:
var
blah: TppField;
begin
blah:=DBPipeline1.FieldObjects['GenDate'];
Text := blah.Foo;
end;
Now the report can't even compile because Foo isn't recognized since
GetPropRec doesn't run.
Please grab my bug project and take a look. It's tiny, uses only standard
D5 classes and exhibits all of this behavior. Alternately, just give me an
example of how to write pass throughs for TField so I can get AsString,
IsNull, and AsDateTime in RAP.
kd
lField: TppField;
begin
lField := Customer.FieldObjects['Company'];
Label1.Caption := lField.AsString;
end;
This code works for me in RAP, RB Enterprise 6.03. All of the RTTI you
mention (except AsDateTime - use AsDouble) is already registered.
Cheers,
Tom Ollar
Digital Metaphors Corporation
http://www.digital-metaphors.com
info@digital-metaphors.com