2009-10-13 6 views
2

J'essaie de créer un generic list de références à PointF objets. (Non, je ne cherche pas à créer une liste générique de PointF objets.) Cependant, la ligne suivante ne peut pas compiler:C++/CLI: Listes de boxe et génériques

Generic::List<PointF^> ^pointList; // Generates error C3225 

D'autre part, la création d'un tableau de PointF références fonctionne sans problème comme suit :

array<PointF^> ^points = gcnew array<PointF^>; 

Voici un exemple de programme:

using namespace System; 
using namespace System::Drawing; 
namespace Generic = System::Collections::Generic; 

int main(array<System::String ^> ^args) 
{ 

    array<PointF^> ^points = gcnew array<PointF^>{ 
     nullptr, PointF(0.0f, 0.0f), PointF(1.0f, 0.0f), nullptr 
    }; 

    Generic::List<PointF^> ^pointList; 
    Console::WriteLine(L"Hello World"); 
    return 0; 
} 

Comment puis-je créer une liste générique de PointF références? En d'autres termes, comment puis-je créer une liste générique de boîtes PointF s?

Répondre

4

Il s'agit d'une limite du générique .Net, qui prend uniquement un type compatible CLI, tel qu'un type de valeur ou une référence à un type de référence. Il ne prend pas les types spécifiques C++/CLI comme la sémantique de pile pour les types ref (qui se compilent en finalisation déterministe) ou, dans votre cas, une référence à un type de valeur encadré.

Array est natif de CLI et n'a pas cette restriction.

0

PointF n'est pas une classe, c'est une structure. Vous ne pouvez pas avoir de références à une structure sans l'encadrer à l'intérieur d'un objet.

Vous pouvez avoir une liste de références et Object unbox la référence à PointF chaque fois que vous l'utilisez, ou une liste d'une classe personnalisée qui encapsule une valeur PointF.

Avec des conversions implicites vers et à partir d'une valeur PointF, vous pouvez rendre la boxe et le déballage transparents. Je ne sais pas comment vous écrivez en C++, mais en C#, il ressemblerait à ceci:

public class PointFObject { 

    // encapsulated PointF structure 
    private PointF _value; 

    // constructor 
    public PointFObject(PointF value) { 
     _value = value; 
    } 

    // implicit conversion to a PointF value 
    public static implicit operator PointF(PointFObject obj) { 
     return obj._value; 
    } 

    // implicit conversion from a PointF value 
    public static implicit operator PointFObject(PointF value) { 
     return new PointFObject(value); 
    } 

} 

Maintenant, vous pouvez créer une liste de PointFObject et d'y accéder en tant que liste de valeurs PointF:

List<PointFObject> pointList = new List<PointFObject>(); 
pointList.Add(new PointF(0f, 0f)); 
PointF p = pointList[0]; 
+0

Pourquoi le tableau se compile-t-il sans problème? Le compilateur gère automatiquement la boxe/unboxing dans ce cas. Pourquoi cela ne fonctionnera-t-il pas dans le cas d'une liste générique? –

0

Même si un emplacement de stockage de type PointF et un objet tas référencé par un PointF^ sont différents types de choses, ils sont tous deux décrits par le même objet Type. Le système décide généralement du type de chose que Type représente en fonction de la façon dont le type est utilisé. Si le type PointF est utilisé pour décrire un emplacement de stockage, cet emplacement de stockage sera alloué pour contenir une structure. Le compilateur C++/CLI peut autoriser la déclaration d'une variable PointF^, mais le Framework n'a pas de concept d'une telle chose. Au sein du code C++/CLI, le compilateur peut utiliser un emplacement de stockage de type Object pour contenir une référence à un objet tas PointF, ou il peut utiliser un Object[] pour contenir un tas de telles références; si de tels emplacements ne sont jamais exposés au monde extérieur et que le compilateur ne stocke jamais rien d'autre que des références PointF, le compilateur peut savoir que la cible de toute référence non nulle peut être utilisée en toute sécurité comme PointF. Toutefois, le compilateur ne peut pas exposer de tels emplacements de stockage au code externe, car le système de type n'offre aucun moyen d'indiquer qu'un autre code doit être limité au stockage des références PointF.

0

Comme d'autres l'ont mentionné, les types génériques n'acceptent que les paramètres de type compatibles CLS. Puisque PointF^ n'est pas compatible CLS, List<PointF^> n'est pas valide.array<> évite ce problème en étant un type de modèle, pas un type générique.

Cependant, il existe une solution de contournement (assez facile): créez un List<Nullable<PointF>>. Votre exemple de programme devient alors:

using namespace System; 
using namespace System::Drawing; 
namespace Generic = System::Collections::Generic; 

int main(array<System::String ^> ^args) 
{ 

    array<Nullable<PointF>> ^points = gcnew array<Nullable<PointF>> { 
     Nullable<PointF>(), Nullable<PointF>(PointF(0.0f, 0.0f)), Nullable<PointF>(PointF(1.0f, 0.0f)), Nullable<PointF>() 
    }; 

    Generic::List<Nullable<PointF>> pointList(points); 
    pointList.Add(PointF(2., 0.)); 
    Console::WriteLine(L"Hello World"); 
    return 0; 
} 
Questions connexes