2011-06-08 3 views
2

Possible en double:
“As” operator for constrained generic typesproblème Generics et CAST

Le code réduit exemple suivant produit une erreur de compilation lors d'une tentative de jeter le type générique en utilisant l'opérateur as. Curieusement, la combinaison de l'opérateur is et d'une distribution dure fonctionne comme prévu.

program Project8; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils, Controls, StdCtrls; 

type 
    TControlWrapperBase = class 
    protected 
    FCtrl : TControl; 
    public 
    constructor Create (Ctrl : TControl); 
    end; 

    TControlWrapper <T : TControl> = class (TControlWrapperBase) 
    public 
    function GetControl : T; 
    end; 


constructor TControlWrapperBase.Create(Ctrl : TControl); 
begin 
FCtrl := Ctrl; 
end; 


function TControlWrapper <T>.GetControl : T; 
begin 
Result := FCtrl as T;  // does not compile: E2010 Incompatible Types: TEdit and TControl 

if FCtrl is T then  // this does work 
    Result := T (FCtrl); 
end; 

var 
    Wrapper : TControlWrapper <TEdit>; 
    MyCtl : TEdit; 

begin 
try 
    MyCtl := TEdit.Create(nil); 
    TControlWrapper <TEdit>.Create (MyCtl).GetControl; 
except 
    on E: Exception do 
    Writeln(E.ClassName, ': ', E.Message); 
end; 

end. 

Comment cette erreur du compilateur peut-elle être surmontée?

+0

Je peux reproduire ceci; La distribution 'as' échoue à compiler avec l'erreur 'incompatible types'. Maintenant, quelle est la question? :-) BTW, la distribution «as» semble superflue. Vous pouvez sécuriser hardcast 'T (FCtrl)' car 'T' est contraint à être un' TControl' (ou descendant). –

+0

@TOndrej: la question est: pourquoi échoue-t-elle? Est-ce un bug de compilateur? – jpfollenius

+0

Oui, personnellement, je le considère comme un bug du compilateur. Il semble logique que la distribution devrait réussir. En outre, le compilateur a les connaissances dont il a besoin pour valider une telle distribution. –

Répondre

1

Ceci est un problème connu: "As" operator for constrained generic types

Cependant, je ne comprends pas pourquoi vous ne pouvez pas l'écrire comme ceci:

type 
    TControlWrapper<T: TControl> = class 
    private 
    FCtrl: T; 
    public 
    property Ctrl: T read FCtrl; 
    end; 
+0

J'ai posté un extrait simplifié. Fondamentalement, nous avons besoin d'accéder au contrôle lorsque vous travaillez avec le type de base, mais que vous voulez obtenir le contrôle spécialisé sans lancer lorsque vous travaillez avec le type dérivé. – jpfollenius

+1

Je viens de réaliser que j'ai moi-même posé la question que vous liez à :) Trop tard déjà ... – jpfollenius

+0

Mon code ci-dessus permettrait tout cela. –

1

Vous avez déjà demandé il y a près the same question plus de 2 ans . Je ne sais pas ce qui a changé dans les génériques Delphi depuis, mais probablement la réponse de Barry Kelly est toujours valide - le compilateur ne peut pas typecast génériques parce

Malheureusement, le compilateur n'est pas assez intelligent pour comprendre que contrainte de type classe signifie que T est garanti avoir la même taille qu'un pointeur .

+2

En fait, nous avons maintenant 3 versions de la même question, toutes posées par @Smasher. Hou la la! –

+0

bien, ouais, j'aurais dû chercher plus attentivement. Mais d'un autre côté, ce n'est pas ma faute si ces choses n'ont pas été réparées depuis plus de deux ans maintenant. BTW: le rapport QC posté par Mason Wheeler dans la question en double est fermé comme fixe ... – jpfollenius

+0

comment est-ce presque la même question? Ce n'est même pas la même erreur de compilation. Avec tous les bugs dans les génériques (en 2009 au moins, et apparemment toujours dans XE), ces différences subtiles importent. – jpfollenius