最近在用C#,觉得它的反射真是不错,在也不用将数据库反回的值一行行,一个属性一个属性的给对象进行赋值了。让代码看着少了很多。
Delphi 也有RTTI 一直没有用过,将大家的代码归纳了一下。给看看能不能更精减和合理一些。
uses TypInfotype
TXRTTI=class public
//给定一个数据集合将值设置给对象 //得到一个对象的属性的数据类型
class function GetObjAttTypeInfo(obj:TPersistent;const AAtt:String;var ATypeInfo:TTypeInfo):Boolean;
//给定一个属性名和值,给对象设置
class function SetObjValue(obj:TPersistent;const AAtt:String;AValue:Variant;ATypeInfo:TTypeInfo):Boolean;overload;
class function SetObjValue(obj:TPersistent;const AAtt:String;AValue:Variant):Boolean;overload;
class function SetObjValueStr(obj:TPersistent;const AAtt:String;AValue:String):Boolean;overload;
//根据一个属性名,得到对象的值
class function GetObjValue(obj:TPersistent;const AAtt:String):Variant;
class function GetObjValueToStr(obj:TPersistent;const AAtt:String):String; end; TXDB=class
//将数据集转换为对象列表
class function DataSetToList(ADOQ:TADOQuery;AClass:TPersistentClass;AList:TList):Integer;
class function DataSetToObj(ADOQ:TADOQuery;obj:TPersistent;ARow:Integer=1):Boolean;
end;implementation{ TXDB }class function TXDB.DataSetToList(ADOQ:TADOQuery;AClass: TPersistentClass; AList: TList): Integer;
var
obj:TPersistent;
i,f:Integer; PropList: PPropList;
ClassTypeInfo: PTypeInfo;
ClassTypeData: PTypeData;
begin
//先取对象属性信息
ClassTypeInfo := AClass.ClassInfo;
ClassTypeData := GetTypeData(ClassTypeInfo);
GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
GetPropInfos(AClass.ClassInfo, PropList); for f:=0 to ADOQ.FieldCount-1 do
begin
ADOQ.Fields[f].Tag:=-1;
for i := 0 to ClassTypeData.PropCount - 1 do
if (PropList[i]^.PropType^.Kind <> tkMethod) then
if SameText(ADOQ.Fields[f].FieldName,PropList[i]^.Name) then
begin
ADOQ.Fields[f].Tag:=i;
Break;
end;
end;
//数据集合转换成对象列表
while Not ADOQ.Eof do
begin
obj:=AClass.Create;
for i:=0 to ADOQ.FieldList.Count-1 do
begin
if (ADOQ.Fields[i].Tag>=0)and(ADOQ.Fields[i].Value<>Null) then
TXRTTI.SetObjValue(obj,ADOQ.Fields[i].FieldName,ADOQ.Fields[i].Value,PropList[ADOQ.Fields[i].Tag]^.PropType^^);
end;
AList.Add(obj);
ADOQ.Next;
end; FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
Result:=AList.Count;
end;class function TXDB.DataSetToObj(ADOQ: TADOQuery;
obj:TPersistent;ARow:Integer=1): Boolean;
var
i,f:Integer; PropList: PPropList;
ClassTypeInfo: PTypeInfo;
ClassTypeData: PTypeData;
begin
//先取对象属性信息
ClassTypeInfo := obj.ClassInfo;
ClassTypeData := GetTypeData(ClassTypeInfo);
GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
GetPropInfos(obj.ClassInfo, PropList); for f:=0 to ADOQ.FieldCount-1 do
begin
ADOQ.Fields[f].Tag:=-1;
for i := 0 to ClassTypeData.PropCount - 1 do
if (PropList[i]^.PropType^.Kind <> tkMethod) then
if SameText(ADOQ.Fields[f].FieldName,PropList[i]^.Name) then
begin
ADOQ.Fields[f].Tag:=i;
Break;
end;
end;
//数据集合转换成对象列表
ADOQ.RecNo:=ARow;
for i:=0 to ADOQ.FieldList.Count-1 do
begin
if (ADOQ.Fields[i].Tag>=0)and(ADOQ.Fields[i].Value<>Null) then
TXRTTI.SetObjValue(obj,ADOQ.Fields[i].FieldName,ADOQ.Fields[i].Value,PropList[ADOQ.Fields[i].Tag]^.PropType^^);
end; FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
Result:=True;
end;{ TXRTTI }class function TXRTTI.GetObjAttTypeInfo(obj: TPersistent;
const AAtt: String;var ATypeInfo:TTypeInfo): Boolean;
var
i:Integer; PropList: PPropList;
ClassTypeInfo: PTypeInfo;
ClassTypeData: PTypeData;
begin
Result:=False;
ClassTypeInfo := obj.ClassType.ClassInfo;
ClassTypeData := GetTypeData(ClassTypeInfo);
GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
GetPropInfos(obj.ClassInfo, PropList); for i := 0 to ClassTypeData.PropCount - 1 do
if (PropList[i]^.PropType^.Kind <> tkMethod) then
if SameText(AAtt,PropList[i]^.Name) then
begin
// AAtt:=PropList[i]^.Name; 属性名不区分大小写,所以不用反正正确的属性值
ATypeInfo:=PropList[i]^.PropType^^;
Result:=True;
Break;
end;
FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
end;class function TXRTTI.GetObjValue(obj: TPersistent;
const AAtt: String): Variant;
var
AKind:TTypeKind;
ATypeInfo:TTypeInfo;
begin
//给定一个属性名称和值,给对应设置
Result:=True;
GetObjAttTypeInfo(obj,AAtt,ATypeInfo); case ATypeInfo.Kind of
tkInteger :Result:=GetInt64Prop(obj,AAtt);
tkFloat :Result:=GetFloatProp(obj,AAtt);
tkInt64 :Result:=GetInt64Prop(obj,AAtt);
tkString :Result:=GetStrProp(obj,AAtt);
tkLString :Result:=GetStrProp(obj,AAtt);
tkWString :Result:=GetStrProp(obj,AAtt);
tkVariant :Result:=GetVariantProp(obj,AAtt);
else
Result:=null;
end;
end;class function TXRTTI.GetObjValueToStr(obj: TPersistent;
const AAtt: String): String;
var
AKind:TTypeKind;
ATypeInfo:TTypeInfo;
begin
//给定一个属性名称和值,给对应设置
GetObjAttTypeInfo(obj,AAtt,ATypeInfo);
case ATypeInfo.Kind of
tkInteger :Result:=IntToStr(GetInt64Prop(obj,AAtt));
tkFloat :Result:=FloatToStr(GetFloatProp(obj,AAtt));
tkInt64 :Result:=IntToStr(GetInt64Prop(obj,AAtt));
tkString :Result:=GetStrProp(obj,AAtt);
tkLString :Result:=GetStrProp(obj,AAtt);
tkWString :Result:=GetStrProp(obj,AAtt);
tkVariant :Result:=VarToStrDef(GetVariantProp(obj,AAtt),'');
else
Result:='';
end;
end;class function TXRTTI.SetObjValue(obj: TPersistent; const AAtt: String;
AValue: Variant):Boolean;
var
ATypeInfo:TTypeInfo;
begin
//给定一个属性名称和值,给对应设置
GetObjAttTypeInfo(obj,AAtt,ATypeInfo);
Result:=SetObjValue(obj,AAtt,AValue,ATypeInfo);
end;class function TXRTTI.SetObjValue(obj: TPersistent; const AAtt: String;
AValue: Variant; ATypeInfo: TTypeInfo): Boolean;
var
i:Integer;
f:Double;
t:Int64;
begin
//给定一个属性名称和值,给对应设置
Result:=True;
case ATypeInfo.Kind of
tkInteger:
begin
i:=AValue;
SetInt64Prop(obj,AAtt,i);
end;
tkFloat :
begin
f:=AValue;
SetFloatProp(obj,AAtt,f);
end;
tkInt64:
begin
t:=AValue;
SetInt64Prop(obj,AAtt,t);
end;
tkString:SetStrProp(obj,AAtt,AValue);
tkLString:SetStrProp(obj,AAtt,AValue);
tkWString:SetStrProp(obj,AAtt,AValue);
tkVariant:SetVariantProp(obj,AAtt,AValue);
else
Result:=False;
end;end;class function TXRTTI.SetObjValueStr(obj: TPersistent; const AAtt: String;
AValue: String): Boolean;
var
AKind:TTypeKind;
i:Integer;
f:Double;
t:Int64;
ATypeInfo:TTypeInfo;
begin
//给定一个属性名称和值,给对应设置
Result:=True;
GetObjAttTypeInfo(obj,AAtt,ATypeInfo); case ATypeInfo.Kind of
tkInteger:
begin
i:=StrToIntDef(AValue,0);
SetInt64Prop(obj,AAtt,i);
end;
tkFloat :
begin
f:=StrToFloatDef(AValue,0);
SetFloatProp(obj,AAtt,f);
end;
tkInt64:
begin
t:=StrToInt64Def(AValue,0);
SetInt64Prop(obj,AAtt,t);
end;
tkString:SetStrProp(obj,AAtt,AValue);
tkLString:SetStrProp(obj,AAtt,AValue);
tkWString:SetStrProp(obj,AAtt,AValue);
tkVariant:SetVariantProp(obj,AAtt,AValue);
else
Result:=False;
end;end;
Delphi 也有RTTI 一直没有用过,将大家的代码归纳了一下。给看看能不能更精减和合理一些。
uses TypInfotype
TXRTTI=class public
//给定一个数据集合将值设置给对象 //得到一个对象的属性的数据类型
class function GetObjAttTypeInfo(obj:TPersistent;const AAtt:String;var ATypeInfo:TTypeInfo):Boolean;
//给定一个属性名和值,给对象设置
class function SetObjValue(obj:TPersistent;const AAtt:String;AValue:Variant;ATypeInfo:TTypeInfo):Boolean;overload;
class function SetObjValue(obj:TPersistent;const AAtt:String;AValue:Variant):Boolean;overload;
class function SetObjValueStr(obj:TPersistent;const AAtt:String;AValue:String):Boolean;overload;
//根据一个属性名,得到对象的值
class function GetObjValue(obj:TPersistent;const AAtt:String):Variant;
class function GetObjValueToStr(obj:TPersistent;const AAtt:String):String; end; TXDB=class
//将数据集转换为对象列表
class function DataSetToList(ADOQ:TADOQuery;AClass:TPersistentClass;AList:TList):Integer;
class function DataSetToObj(ADOQ:TADOQuery;obj:TPersistent;ARow:Integer=1):Boolean;
end;implementation{ TXDB }class function TXDB.DataSetToList(ADOQ:TADOQuery;AClass: TPersistentClass; AList: TList): Integer;
var
obj:TPersistent;
i,f:Integer; PropList: PPropList;
ClassTypeInfo: PTypeInfo;
ClassTypeData: PTypeData;
begin
//先取对象属性信息
ClassTypeInfo := AClass.ClassInfo;
ClassTypeData := GetTypeData(ClassTypeInfo);
GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
GetPropInfos(AClass.ClassInfo, PropList); for f:=0 to ADOQ.FieldCount-1 do
begin
ADOQ.Fields[f].Tag:=-1;
for i := 0 to ClassTypeData.PropCount - 1 do
if (PropList[i]^.PropType^.Kind <> tkMethod) then
if SameText(ADOQ.Fields[f].FieldName,PropList[i]^.Name) then
begin
ADOQ.Fields[f].Tag:=i;
Break;
end;
end;
//数据集合转换成对象列表
while Not ADOQ.Eof do
begin
obj:=AClass.Create;
for i:=0 to ADOQ.FieldList.Count-1 do
begin
if (ADOQ.Fields[i].Tag>=0)and(ADOQ.Fields[i].Value<>Null) then
TXRTTI.SetObjValue(obj,ADOQ.Fields[i].FieldName,ADOQ.Fields[i].Value,PropList[ADOQ.Fields[i].Tag]^.PropType^^);
end;
AList.Add(obj);
ADOQ.Next;
end; FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
Result:=AList.Count;
end;class function TXDB.DataSetToObj(ADOQ: TADOQuery;
obj:TPersistent;ARow:Integer=1): Boolean;
var
i,f:Integer; PropList: PPropList;
ClassTypeInfo: PTypeInfo;
ClassTypeData: PTypeData;
begin
//先取对象属性信息
ClassTypeInfo := obj.ClassInfo;
ClassTypeData := GetTypeData(ClassTypeInfo);
GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
GetPropInfos(obj.ClassInfo, PropList); for f:=0 to ADOQ.FieldCount-1 do
begin
ADOQ.Fields[f].Tag:=-1;
for i := 0 to ClassTypeData.PropCount - 1 do
if (PropList[i]^.PropType^.Kind <> tkMethod) then
if SameText(ADOQ.Fields[f].FieldName,PropList[i]^.Name) then
begin
ADOQ.Fields[f].Tag:=i;
Break;
end;
end;
//数据集合转换成对象列表
ADOQ.RecNo:=ARow;
for i:=0 to ADOQ.FieldList.Count-1 do
begin
if (ADOQ.Fields[i].Tag>=0)and(ADOQ.Fields[i].Value<>Null) then
TXRTTI.SetObjValue(obj,ADOQ.Fields[i].FieldName,ADOQ.Fields[i].Value,PropList[ADOQ.Fields[i].Tag]^.PropType^^);
end; FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
Result:=True;
end;{ TXRTTI }class function TXRTTI.GetObjAttTypeInfo(obj: TPersistent;
const AAtt: String;var ATypeInfo:TTypeInfo): Boolean;
var
i:Integer; PropList: PPropList;
ClassTypeInfo: PTypeInfo;
ClassTypeData: PTypeData;
begin
Result:=False;
ClassTypeInfo := obj.ClassType.ClassInfo;
ClassTypeData := GetTypeData(ClassTypeInfo);
GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
GetPropInfos(obj.ClassInfo, PropList); for i := 0 to ClassTypeData.PropCount - 1 do
if (PropList[i]^.PropType^.Kind <> tkMethod) then
if SameText(AAtt,PropList[i]^.Name) then
begin
// AAtt:=PropList[i]^.Name; 属性名不区分大小写,所以不用反正正确的属性值
ATypeInfo:=PropList[i]^.PropType^^;
Result:=True;
Break;
end;
FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
end;class function TXRTTI.GetObjValue(obj: TPersistent;
const AAtt: String): Variant;
var
AKind:TTypeKind;
ATypeInfo:TTypeInfo;
begin
//给定一个属性名称和值,给对应设置
Result:=True;
GetObjAttTypeInfo(obj,AAtt,ATypeInfo); case ATypeInfo.Kind of
tkInteger :Result:=GetInt64Prop(obj,AAtt);
tkFloat :Result:=GetFloatProp(obj,AAtt);
tkInt64 :Result:=GetInt64Prop(obj,AAtt);
tkString :Result:=GetStrProp(obj,AAtt);
tkLString :Result:=GetStrProp(obj,AAtt);
tkWString :Result:=GetStrProp(obj,AAtt);
tkVariant :Result:=GetVariantProp(obj,AAtt);
else
Result:=null;
end;
end;class function TXRTTI.GetObjValueToStr(obj: TPersistent;
const AAtt: String): String;
var
AKind:TTypeKind;
ATypeInfo:TTypeInfo;
begin
//给定一个属性名称和值,给对应设置
GetObjAttTypeInfo(obj,AAtt,ATypeInfo);
case ATypeInfo.Kind of
tkInteger :Result:=IntToStr(GetInt64Prop(obj,AAtt));
tkFloat :Result:=FloatToStr(GetFloatProp(obj,AAtt));
tkInt64 :Result:=IntToStr(GetInt64Prop(obj,AAtt));
tkString :Result:=GetStrProp(obj,AAtt);
tkLString :Result:=GetStrProp(obj,AAtt);
tkWString :Result:=GetStrProp(obj,AAtt);
tkVariant :Result:=VarToStrDef(GetVariantProp(obj,AAtt),'');
else
Result:='';
end;
end;class function TXRTTI.SetObjValue(obj: TPersistent; const AAtt: String;
AValue: Variant):Boolean;
var
ATypeInfo:TTypeInfo;
begin
//给定一个属性名称和值,给对应设置
GetObjAttTypeInfo(obj,AAtt,ATypeInfo);
Result:=SetObjValue(obj,AAtt,AValue,ATypeInfo);
end;class function TXRTTI.SetObjValue(obj: TPersistent; const AAtt: String;
AValue: Variant; ATypeInfo: TTypeInfo): Boolean;
var
i:Integer;
f:Double;
t:Int64;
begin
//给定一个属性名称和值,给对应设置
Result:=True;
case ATypeInfo.Kind of
tkInteger:
begin
i:=AValue;
SetInt64Prop(obj,AAtt,i);
end;
tkFloat :
begin
f:=AValue;
SetFloatProp(obj,AAtt,f);
end;
tkInt64:
begin
t:=AValue;
SetInt64Prop(obj,AAtt,t);
end;
tkString:SetStrProp(obj,AAtt,AValue);
tkLString:SetStrProp(obj,AAtt,AValue);
tkWString:SetStrProp(obj,AAtt,AValue);
tkVariant:SetVariantProp(obj,AAtt,AValue);
else
Result:=False;
end;end;class function TXRTTI.SetObjValueStr(obj: TPersistent; const AAtt: String;
AValue: String): Boolean;
var
AKind:TTypeKind;
i:Integer;
f:Double;
t:Int64;
ATypeInfo:TTypeInfo;
begin
//给定一个属性名称和值,给对应设置
Result:=True;
GetObjAttTypeInfo(obj,AAtt,ATypeInfo); case ATypeInfo.Kind of
tkInteger:
begin
i:=StrToIntDef(AValue,0);
SetInt64Prop(obj,AAtt,i);
end;
tkFloat :
begin
f:=StrToFloatDef(AValue,0);
SetFloatProp(obj,AAtt,f);
end;
tkInt64:
begin
t:=StrToInt64Def(AValue,0);
SetInt64Prop(obj,AAtt,t);
end;
tkString:SetStrProp(obj,AAtt,AValue);
tkLString:SetStrProp(obj,AAtt,AValue);
tkWString:SetStrProp(obj,AAtt,AValue);
tkVariant:SetVariantProp(obj,AAtt,AValue);
else
Result:=False;
end;end;
解决方案 »
- 请教一个编译错误:常量对象不能作为变量参数传递
- 当我查看某个窗体时提示TDBDateTimeEaditEhEh类没有找到是怎么回事?
- QuickRep 报表的简单问题,请指教?
- 如何把一个含有多个sheet的excel文件分成多个excel文件,而每个excel文件中包含一个sheet?
- 如何获得ClientDataSet待执行的SQL语句?
- 不用form的属性,通过api能不能使窗体永远在最前面?
- 绝对有价值回答----------------?
- ★★调查:人事管理软件,谁更好?
- 关于unit单元文件的结构问题
- delphi的dll库中语句执行返回程序出错!dll中加上不相关的语句就可以!是borland的一个大bug!!!?
- speedbutton鼠标按下的问题
- 请教,这个网站是什么语言写的
D1: Longword;
D2: Word;
D3: Word;
D4: array[0..7] of Byte;
end;TGUID是record,不是TObject
Forcing RTTI on record types
而d2010增强了rtti,TGUID也会生成TypeInfo,所以再用它做类型的属性就可以通过rtti获取了。这也是d2010编译出来的文件大了许多的原因
RTTI will be emitted if a record contains a “managed type” like dynamic arrays, strings, interfaces or reference to functions在高版本中好像出了strict private 语法,Seamour对这个有研究吗
-------------------------不是任何类型在published下都有类型信息的。
简单的针对表的增,删,改功能,代码量有90%的减少。只要给定表名和表中一行数据所对应的类名就可以完成。定义了基类
TRowObjectClass=class of TRowObject;
TRowObject=class
GUID:String; //
ItemID:Integer;//唯一递增标识
end;TRowObjectList=class //保存TRowObject数据集
private
FList:TList;end;TNodeObjectList=class(TRowObjectList)//保存TNodeObject数据集end;TNodeObject=class(TRowObject)
PGUID:String;//上级节点的标识
FChildList:TNodeObjectList;
end;表中都有 ItemID,GUID ,PGUID(树表中) 这几个字段TXDB.GetRowList(AClass:TRowObjectClass,ATableName:String)
begin
//返回表中的所有数据
end;软件完成后在整理一下,搞个可用的例子出来。大家给点意见,怎么能做的更好。
保存主要两种方式class function TXDB.SaveObject(ADOQ:TADOQuery;ATableName:String;obj:TRowObject):Boolean;
根据 obj.ItemID>0 则是添加 obj.ItemID=0 则是修改。
用SQLServer 数据库则在Inster 后直接返回新增加行的 ItemID
用Access 数据库则在Insert后用GUID 反查出 ItemID修改的时候用 Where ItemID=obj.ItemID 条件,保存除去 GUID 外的其它属性
如用户列表对象
TUserList=class
function SaveUser(obj:TUserInfo):Boolean;
end;function TUserList.SaveUser(obj:TUserInfo):Boolean;
begin
Result:=TXDB.SaveObject(GetADOQ,'UserList',obj);
end;
界面上数据集显示到 TVirtualStringTree 中,直接在 格式中修改时调用
function SaveObjectCell(obj:TRowObject;const Att,Value:String):Boolean; 来完成对一个属性的修改。一下步想参考 Hibermate 的方式,实现 One-To-One ,one-to-many,one-to-many 这些模式的数据的显示。
能达到不用为每个类写实现SQL就可以完成持久化保存,读取,删除的工作。其它人也有实现的,但学习别的代码的时候不如自己去实现一下用起来更顺手一些。
----------------------
写错了。应该是
-------------------
根据 obj.ItemID>0 则是修改 obj.ItemID=0 则是添加。
而且,对象里的很多属性也只是运行时临时使用的,并不希望保存的
数据库记录里的一些字段也是不希望给对象直接使用的RTTI只是给 运行时按字符串的属性名找属性 提供实现手段。
如果用数据库记录或xml、ini来保存一个对象的主要属性,也是可以 运行时按字符串的属性名找属性 的。