2012-04-17 28 views
11

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

+4

Bạn đang sử dụng phiên bản delphi nào? – zz1433

+0

OK rằng tôi quên - Tôi đang sử dụng Delphi XE – OZ8HP

Trả lời

10

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; 
+1

Xin lỗi vì sự chậm trễ trong việc trở lại - bận rộn với các dự án khác :-) – OZ8HP

+0

@ David, cảm ơn! Đó là những gì tôi đã làm trong [sửa đổi ban đầu ”] của tôi (http://stackoverflow.com/revisions/10189686/1). Tôi không biết tại sao tôi lại phá vỡ nó theo cách đó ... – TLama

15

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

+0

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

+0

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

Các vấn đề liên quan