Tôi có một lớp trong ứng dụng Delphi của mình, nơi tôi muốn một cách dễ dàng và năng động để đặt lại tất cả các thuộc tính chuỗi thành '' và tất cả thuộc tính boolean thành False Theo như tôi có thể thấy trên trang web có thể tạo ra một vòng lặp nào đó, nhưng làm thế nào để làm điều đó không rõ ràng với tôi.Cách lặp lại tất cả các thuộc tính trong một Lớp
Trả lời
Xin lưu ý, các mã sau đây chỉ có tác dụng đối với tài sản được công bố của một lớp học! Ngoài ra, thể hiện của một lớp được chuyển đến hàm bên dưới phải có ít nhất phần được xuất bản được xác định!
Dưới đây là cách đặt giá trị thuộc tính chuỗi đã xuất bản thành chuỗi rỗng và giá trị boolean thành False bằng cách sử dụng kiểu RTTI cũ.
Nếu bạn có Delphi cũ hơn Delphi 2009, bạn có thể thiếu loại tkUString. Nếu vậy, chỉ cần loại bỏ
nó từ đoạn mã sau:
uses
TypInfo;
procedure ResetPropertyValues(const AObject: TObject);
var
PropIndex: Integer;
PropCount: Integer;
PropList: PPropList;
PropInfo: PPropInfo;
const
TypeKinds: TTypeKinds = [tkEnumeration, tkString, tkLString, tkWString,
tkUString];
begin
PropCount := GetPropList(AObject.ClassInfo, TypeKinds, nil);
GetMem(PropList, PropCount * SizeOf(PPropInfo));
try
GetPropList(AObject.ClassInfo, TypeKinds, PropList);
for PropIndex := 0 to PropCount - 1 do
begin
PropInfo := PropList^[PropIndex];
if Assigned(PropInfo^.SetProc) then
case PropInfo^.PropType^.Kind of
tkString, tkLString, tkUString, tkWString:
SetStrProp(AObject, PropInfo, '');
tkEnumeration:
if GetTypeData(PropInfo^.PropType^)^.BaseType^ = TypeInfo(Boolean) then
SetOrdProp(AObject, PropInfo, 0);
end;
end;
finally
FreeMem(PropList);
end;
end;
Đây là một mã kiểm tra đơn giản (lưu ý các thuộc tính phải được công bố, nếu không có thuộc tính được công bố trên lớp, phần ít nhất có sản phẩm nào được công bố phải đó):
type
TSampleClass = class(TObject)
private
FStringProp: string;
FBooleanProp: Boolean;
published
property StringProp: string read FStringProp write FStringProp;
property BooleanProp: Boolean read FBooleanProp write FBooleanProp;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
SampleClass: TSampleClass;
begin
SampleClass := TSampleClass.Create;
try
SampleClass.StringProp := 'This must be cleared';
SampleClass.BooleanProp := True;
ResetPropertyValues(SampleClass);
ShowMessage('StringProp = ' + SampleClass.StringProp + sLineBreak +
'BooleanProp = ' + BoolToStr(SampleClass.BooleanProp));
finally
SampleClass.Free;
end;
end;
nếu bạn là người dùng Delphi 2010 (và cao hơn) thì có một đơn vị RTTI mới (rtti.pas). bạn có thể sử dụng nó để lấy thông tin thời gian chạy về lớp của bạn và thuộc tính của nó (thuộc tính công khai theo mặc định, nhưng bạn có thể sử dụng chỉ thị biên dịch {$RTTI}
để bao gồm thông tin trường được bảo vệ và riêng tư). Ví dụ chúng ta có lớp thử nghiệm tiếp theo với 3 trường công khai (1 trường boolean và 2 trường chuỗi (một trong số chúng là chỉ đọc)).
TTest = class(TObject)
strict private
FString1 : string;
FString2 : string;
FBool : boolean;
public
constructor Create();
procedure PrintValues();
property String1 : string read FString1 write FString1;
property String2 : string read FString2;
property BoolProp : boolean read FBool write FBool;
end;
constructor TTest.Create();
begin
FBool := true;
FString1 := 'test1';
FString2 := 'test2';
end;
procedure TTest.PrintValues();
begin
writeln('string1 : ', FString1);
writeln('string2 : ', FString2);
writeln('bool: ', BoolToStr(FBool, true));
end;
để liệt kê tất cả các thuộc tính của đối tượng và thiết lập nó giá trị nào mặc định bạn có thể sử dụng giống như mã dưới đây. Trước tiên, bạn phải init cấu trúc TRttiContext
(nó không phải là cần thiết, bởi vì nó là một bản ghi). Sau đó, bạn sẽ nhận được thông tin rtti về obejct của bạn, sau đó bạn có thể lặp lại các thuộc tính của bạn và lọc nó (bỏ qua các thuộc tính chỉ đọc và khác với boolean và stirng). Đưa vào tài khoản là có vài loại dây: tkUString, tkString và những người khác (hãy nhìn vào TTypeKind
trong typinfo.pas
)
TObjectReset = record
strict private
public
class procedure ResetObject(obj : TObject); static;
end;
{ TObjectReset }
class procedure TObjectReset.ResetObject(obj: TObject);
var ctx : TRttiContext;
rt : TRttiType;
prop : TRttiProperty;
value : TValue;
begin
ctx := TRttiContext.Create();
try
rt := ctx.GetType(obj.ClassType);
for prop in rt.GetProperties() do begin
if not prop.IsWritable then continue;
case prop.PropertyType.TypeKind of
tkEnumeration : value := false;
tkUString : value := '';
else continue;
end;
prop.SetValue(obj, value);
end;
finally
ctx.Free();
end;
end;
mã đơn giản để kiểm tra:
var t : TTest;
begin
t := TTest.Create();
try
t.PrintValues();
writeln('reset values'#13#10);
TObjectReset.ResetObject(t);
t.PrintValues();
finally
readln;
t.Free();
end;
end.
và kết quả là
string1 : test1
string2 : test2
bool: True
reset values
string1 :
string2 : test2
bool: False
cũng hãy xem Thuộc tính, bạn nên đánh dấu các thuộc tính (mà bạn cần để thiết lập lại) với một số thuộc tính, và có thể có giá trị mặc định như:
[ResetTo('my initial value')]
property MyValue : string read FValue write FValue;
sau đó bạn có thể lọc chỉ tính Mà được đánh dấu bằng ResetToAttribute
Chắc chắn tôi có rất nhiều thông tin để làm việc ngay bây giờ Tôi nghĩ giải pháp của teran sẽ là giải pháp tôi sẽ thử nghiệm. Nhưng tôi sẽ quay lại. – OZ8HP
Tôi viết lại câu trả lời vì tôi đã đọc sai câu hỏi của bạn (bạn cần nó cho các thành phần). Tuy nhiên đối với các lớp của riêng bạn với các thuộc tính khác ngoài được xuất bản thì kiểu RTTI cũ không sử dụng được. Vì vậy, chắc chắn làm theo cách này ;-) – TLama
Bạn đang sử dụng phiên bản delphi nào? – zz1433
OK rằng tôi quên - Tôi đang sử dụng Delphi XE – OZ8HP