2012-10-05 1 views
3
type 
    TForm72 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations }  
    end; 

    TTestForm = class(TForm) 
    public 
    constructor CreateTest(AOwner: TComponent); virtual; 
    end; 

    TTestForm1 = class(TTestForm)  
    public 
    constructor CreateTest(AOwner: TComponent); override; 
    end; 

    TTest<T: TTestForm, constructor> = class(TObject) 
    public 
    class procedure Test; 
    end; 

var 
    Form72: TForm72; 

implementation 

{$R *.dfm} 

procedure TForm72.FormCreate(Sender: TObject); 
begin 
    TTest<TTestForm1>.Test; 
end; 

{ TTest<T> } 

class procedure TTest<T>.Test; 
var 
    F: T; 
begin 
    F := T.CreateTest(Application); 
    Form72.Caption := F.Name; 
end; 

{ TTestForm } 

constructor TTestForm.CreateTest(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 
end; 

{ TTestForm1 } 

constructor TTestForm1.CreateTest(AOwner: TComponent); 
begin 
    inherited; 
    Caption := 'Bang'; 
end; 

end. 

XE2에서 컴파일이 코드를 컴파일하지만 "[DCC32 오류] Unit71.pas (55)와 함께 실패하지 않습니다 이유 : E2010 호환되지 않는 유형 : 'T'와 '절차, 지정되지 않은 포인터 나 형식이 지정되지 않은 매개 변수 ''를 사용합니다. 내가 잘못했거나 컴파일러가 잘못 했어?이 코드는 XE3

답변

4

사실이 코드는 XE2의 컴파일러 버그를 강조 표시합니다. XE2에서는 코드가 컴파일되지 않아야 컴파일됩니다. constructor 제약 조건을 제거하고 컴파일

 
E2568 Can't create new instance without CONSTRUCTOR constraint in type 
parameter declaration 

실패하지만 constructor 제약 단지 클래스는 매개 변수가없는 생성자가 있다고 주장한다. documentation 상태 :

생성자 제약

유형 파라미터는 상기 예약어 "생성자"의 0 또는 1 인스턴스에 의해 제한 될 수있다. 즉, 실제 인수 형식 은 기본 생성자 (public 매개 변수없는 생성자)를 정의하는 클래스 여야하므로 제네릭 형식 내의 메서드는 인수 형식 인 기본 생성자를 사용하여 인수 형식의 인스턴스를 생성 할 수 있습니다. 인수 유형 자체에 대한 내용 (최소 기본 유형 요구 사항 없음).

constructor 제약 조건의 존재 여부가이 코드에 영향을 준다는 사실은 XE2 컴파일러에 결함이 있음을 나타냅니다.


XE3에서 코드를 올바르게 컴파일하지 못했습니다. T.Create 구문을 사용하여 생성자를 호출하는 유일한 방법은 constructor 제약 조건을 사용하고 매개 변수없는 생성자를 호출하는 경우입니다. 여기서는 그렇지 않으므로 XE3은 컴파일 오류를 올바르게보고합니다.

컴파일하려면 일부 캐스팅이 필요합니다.

F := T(TTestForm(T).CreateTest(Application)); 

생성자의 델파이 제네릭 구현의 처리의 단점 중 일부를 해결하기 위해 well-known trick이다. 지저분 해 보일지라도,이 코드는 언어 설계자가 의도 한 것입니다. 제 생각에는 동작의 변화는 버그 수정으로 인한 것이며 XE3은 의도 된대로 동작합니다.

+0

답장을 보내 주셔서 감사합니다. 나는 진보에 직면 해있다. 귀하의 수정과 함께 컴파일했습니다. 그러나 액세스 위반으로 실행시 실패합니다. – user1723322

+0

죄송합니다. 나는 잘 집중된 독자가 아니었다. 사실 F : = T (TTestFormClass (T) .CreateTest (Application)); 잘 작동 – user1723322

+0

완료. 발언처럼 -이 유형의 캐스팅 운동은 추한 것 같습니다. 아이디어 제네릭에서는 계량 캐스팅을 피하기 위해 유형 캐스팅을 피할 수있는 방법을 고안했습니다. – user1723322