2010-01-25 29 views
12

Xét như một liệt kê:Delphi 2010 RTTI: Khám phá Enumerations

type 
    TTypeOfData = (
    [XmlName('ABC')] todABC, 
    [XmlName('DEF')] todDEF, 
    [XmlName('GHI')] todGHI 
); 

đâu XmlName là một thuộc tính tùy chỉnh sử dụng để xác định chuỗi tuần tự cho các thành viên của liệt kê này.

Làm cách nào để khám phá các thuộc tính được đính kèm với từng thành viên của điều tra này?

Trả lời

14

Thuộc tính được liên kết với các phần tử trong liệt kê hiện không được lưu trữ trong dữ liệu Win32 RTTI trong tệp thực thi. RTTI đã chịu trách nhiệm cho sự gia tăng công bằng về kích thước của các tệp thực thi, vì vậy một số dòng phải được vẽ ở đâu đó. Các thuộc tính trong Delphi Win32 được hỗ trợ trên các kiểu, trên các trường của bản ghi và các trường, phương thức, tham số của chúng và các thuộc tính của các lớp.

Khai báo thuộc tính không gây ra lỗi do khả năng tương thích ngược với Delphi cho .NET.

+8

Giải thích tốt trên. Nhưng IMO trong trường hợp đó, họ phải gây ra cảnh báo "tính năng ngôn ngữ không được hỗ trợ", giống như việc sử dụng thuộc tính không hợp lệ khác. –

3

Những là một cái nhìn tổng quan tốt của RTTI trong Delphi 2010 trên trang web: http://robstechcorner.blogspot.com/2009/09/so-what-is-rtti-rtti-is-acronym-for-run.html

Bạn có thể nhận các giá trị liệt kê và sao lưu các ordinals sử dụng "OLD" chức năng RTTI trong đơn vị TypInfo (GetEnumValue, GetEnumName). Và cắt bỏ các chữ thường bạn nhận được kết quả tương tự như trên nhưng nó không phải là linh hoạt.

17

Trong khi Barry trả lời rõ ràng câu hỏi của bạn liên quan đến các thuộc tính trên các thành phần enum, tôi sẽ bị đâm vào một đề xuất khác. Từ ví dụ của bạn, bạn đang đặt trước mỗi phần tử enum với 'tod' như là truyền thống trong Delphi vì các phần tử enum có phạm vi toàn cục (ví dụ: nếu bạn có một định danh todABC trong phạm vi ngoài các phần tử endABC enum, bạn có thể nhận được một số hành vi kỳ lạ).

Bắt đầu từ D2007, chúng tôi đã giới thiệu khái niệm "enums enums", khi được bật, yêu cầu bạn phải đủ điều kiện phần tử enum với số nhận dạng của chính enum. Ví dụ:

{$SCOPEDENUMS ON} 
type 
    TTypeOfData = (ABC,DEF,GHI); 

Sẽ yêu cầu bạn tham chiếu đến phần tử ABC như TTypeOfData.ABC. Điều này cho phép bạn sử dụng các định danh phần tử enum không có tiền tố và không chạy nguy cơ có xung đột vì các phần tử được "phạm vi" để liệt kê. Bất kỳ enum nào được khai báo trong khi {$ SCOPEDENUMS} được kích hoạt sẽ hoạt động theo cách này.

Cho rằng, bây giờ bạn có thể sử dụng RTTI một cách an toàn để lấy tên phần tử enum thực tế theo định dạng bạn muốn.

+0

Cảm ơn bạn Allen, Đó là một ví dụ không tốt. Điều tra của tôi là một chuỗi phức tạp hơn và được tuần tự hóa không giống với các thành viên điều tra. – ZeDalaye

+0

Phew, đó là mát mẻ! Không biết rằng, luôn luôn không thích sự lộn xộn toàn cầu so với tiền tố xấu xí thỏa hiệp người ta phải thực hiện với enum ... –

+0

@ZeDalaye, Tôi nghi ngờ rằng, tuy nhiên nếu có một số nugget hữu ích trong đề nghị của tôi ... không, tôi chắc rằng ai đó có thể thấy nó hữu ích. –

1

Đối với những người đang interrested trong một giải pháp thực tế cho vấn đề đó, tôi giải quyết nó theo cách đó:

type 
    TTypeOfData = (todABC, todDEF, todGHI); 

    TMySerializableClass = class 
    private 
    FType: TTypeOfData; 
    public 
    property &Type: TTypeOfData read FType write FType; 
    class function TypeOfDataAsString(&Type: TTypeOfData): String; 
    end; 

implementation 

class function TMySerializableClass.TypeOfDataAsString(&Type: TTypeOfData): String; 
const 
    TYPE_STRING: array[TypeOfDataAsString] of String = ('ABC', 'DEF', 'GHI); 
begin 
    Result := TYPE_STRING[&Type]; 
end; 

Và sau đó, trong các mã serialization, tôi sử dụng RTTI để tìm kiếm một chức năng lớp conventionnaly tên AsString và gọi nó bằng TValue:

procedure Serialize(const V: TValue); 
var 
    N: String; 
    T: TRttiType; 
    F: TRttiField; 
    M: TRttiMethod; 
    R: TValue; 
begin 
    case V.TypeInfo^.Kind of 
    tkEnumeration: 
    begin 
    T := Ctx.GetType(TypeInfo(TMySerializableClass)); 
    N := V.TypeInfo.Name + 'AsString'; 
    if N[1] = 'T' then 
     Delete(N, 1, 1); 
    M := T.GetMethod(N); 
    if (M <> nil) and M.IsClassMethod and (M.MethodKind = mkClassFunction) and (M.ReturnType.TypeKind = tkUString) then 
    begin 
     R := M.Invoke(TTicket, [V]); 
     // serialize R.AsString 
    end; 
    end; 
    ... 
end; 
+1

Đây là giải pháp hợp lý. Tôi cũng rất thích đề xuất của Allen Bauer. –

+0

Làm thế nào '&' trong 'thuộc tính & Loại' cho? – Shannon

+0

Loại là một từ dành riêng trong Delphi. Tiền tố với & làm cho có thể sử dụng từ đó như một định danh. – ZeDalaye

3

Ok tôi nghĩ mình đã tìm được giải pháp tốt hơn. Tôi tuyên bố loại thuộc tính mới, ví dụ::

TEnumAttribute = class (TCustomAttribute) 
    private 
    FCaption : string; 
    public 
    constructor Create (const Caption : string); 
    property Caption : string read FCaption write FCaption; 
end; 

Bây giờ tôi thêm các thuộc tính để liệt kê của tôi:

[TEnumAttribute ('Normal')] 
[TEnumAttribute ('High')] 
TExampleEnum = (eeNormal,eeHigh); 

Bây giờ nó rất dễ dàng để truy cập vào các thuộc tính bởi thứ tự của nó:

RttiType := RttiContext.FindType ('ExampleUnit.TExampleEnum'); 
RttiAttributes := Rttitype.GetAttributes; 
Test := TEnumAttributes(RttiAttributes[index]).Caption; 
+0

tuyệt vời !! câu trả lời gần nhất cho câu hỏi này .. –

0

tôi sử dụng và mảng của chuỗi trong phần const:

type 
    TTypeOfData = (
    todABC, 
    todDEF, 
    todGHI 
); 

const 
    TypeOfDataText: array[TTypeOfData] of string = (
    'ABC', 
    'DEF', 
    'GHI' 
); 
Các vấn đề liên quan