2012-02-29 4 views
11

Hãy xem xét ví dụ sau (Tôi đang sử dụng Delphi XE):Delphi XE: constructor lớp không được gọi trong một lớp học sử dụng Generics

program Test; 

{$APPTYPE CONSOLE} 

type 
    TTestClass<T> = class 
    private 
    class constructor CreateClass(); 
    public 
    constructor Create(); 
    end; 

class constructor TTestClass<T>.CreateClass(); 
begin 
    // class constructor is not called. this line never gets executed! 
    Writeln('class created'); 
end; 

constructor TTestClass<T>.Create(); 
begin 
    // this line, of course, is printed 
    Writeln('instance created'); 
end; 

var 
    test: TTestClass<Integer>; 

begin 
    test := TTestClass<Integer>.Create(); 
    test.Free(); 
end. 

Các constructur lớp không bao giờ được gọi là và do đó dòng 'lớp tạo 'không được in. Tuy nhiên, nếu tôi xóa tổng quát và thực hiện TTestClass<T> thành một lớp tiêu chuẩn TTestClass, mọi thứ hoạt động như mong đợi.

Tôi có thiếu thứ gì đó với generics không? Hay đơn giản là nó không hoạt động?

Bất kỳ suy nghĩ nào về điều này sẽ được ứng dụng!

Xin cảm ơn, --Stefan--

+0

[tài liệu] (http://docwiki.embarcadero.com/RADStudio/en/Methods#Class_Constructors) nêu rõ: "Lưu ý: Trình tạo lớp cho lớp hoặc bản ghi chung có thể thực thi nhiều lần. Số lần chính xác constructor lớp được thực hiện trong trường hợp này phụ thuộc vào số phiên bản chuyên biệt của kiểu generic. Ví dụ, hàm tạo lớp cho một lớp TList chuyên dụng có thể thực thi nhiều lần trong cùng một ứng dụng. " Nhưng nó trông hơi giống một con bọ vậy. –

+0

Có. Tôi cũng đọc nó. Trừ khi "nhiều lần" bao gồm 0 lần, điều này thực sự trông giống như một lỗi. – Schafsmann

+0

Quy tắc chung: Đừng cố gắng tạo một ứng dụng .dpr tự chứa. Luôn có ít nhất một đơn vị và giữ tất cả mọi thứ trong các tệp DPR mà bạn có thể giữ lại. –

Trả lời

9

Trông giống như lỗi trình biên dịch. Cùng một mã hoạt động nếu bạn di chuyển khai báo và triển khai TTestClass đến một đơn vị riêng biệt.

unit TestClass; 

interface 
type 
    TTestClass<T> = class 
    private 
    class constructor CreateClass(); 
    public 
    constructor Create(); 
    end; 

var 
    test: TTestClass<Integer>; 

implementation 

class constructor TTestClass<T>.CreateClass(); 
begin 
    Writeln('class created'); 
end; 

constructor TTestClass<T>.Create(); 
begin 
    Writeln('instance created'); 
end; 

end. 
+1

+1 Tôi đã tự mình đạt được kết luận chính xác! –

+1

Tuyệt vời, cảm ơn bạn đã giải quyết điều này! Tôi cũng sẽ +1 nếu tôi có thể. Trên thực tế tôi đã có lớp học của tôi trong đơn vị riêng của nó nhưng tôi đã sử dụng nó trong tập tin .dpr chỉ. Vì vậy, câu trả lời cho câu hỏi là: Các hàm tạo lớp của các lớp chung không chạy cho các đối tượng được khởi tạo trong tệp .dpr. – Schafsmann

+0

và tôi đã làm :) – Schafsmann

11

Tôi có thể xác nhận đây là lỗi. Nếu instantiation duy nhất của class nằm trong file .dpr, thì class constructor sẽ không chạy. Nếu bạn tạo một đơn vị khác, tức là một tệp .pas riêng biệt và khởi tạo một TTestClass<Integer> từ đó, thì trình tạo lớp của bạn sẽ chạy.

Tôi đã gửi QC#103798.

+1

Vẫn không cố định trong XE5. Điều tồi tệ nhất là bạn phải khai báo hoặc khởi tạo một biến trong tệp .pas riêng biệt. Và bạn phải làm điều đó cho mọi T được sử dụng trong chương trình của bạn !! –

+2

Vẫn không cố định trong XE8 @LURD –

+0

@LURD EBMT dường như buộc các nhà lập trình giữ tay khỏi tệp DPR như đã đề cập trong WarrenP. – Fr0sT