问题
I am trying to create a generic list of references to PointF
objects. (No, I am not looking to create a generic list of PointF
objects.) However, the following line fails to compile:
Generic::List<PointF^> ^pointList; // Generates error C3225
On the other hand, creating an array of PointF
references works without a problem as follows:
array<PointF^> ^points = gcnew array<PointF^>;
Here is a sample program:
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;
}
How do I create a generic list of PointF
references? In other words, how do I create a generic list of boxed PointF
s?
回答1:
It is a limit of the .Net generic, which only takes a CLI complient type such as a value type or a reference to a reference type. It does not take C++/CLI-specific types like stack semantics for ref types (which compiles into deterministic finalization) or, in you case, a reference to a boxed value type.
Array is native to CLI and does not have this restriction.
回答2:
PointF
is not a class, it's a structure. You can't have references to a structure without boxing it inside an object.
You can either have a list of Object
references and unbox the reference to PointF
whenever you use it, or a list of a custom class that encapsulates a PointF
value.
With implicit conversions to and from a PointF
value you can make the boxing and unboxing transparent. I'm not sure how you write it in C++, but in C# it would look like this:
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);
}
}
Now you can create a list of PointFObject and access them as a list of PointF values:
List<PointFObject> pointList = new List<PointFObject>();
pointList.Add(new PointF(0f, 0f));
PointF p = pointList[0];
回答3:
Even though a storage location of type PointF
and a heap object referred to by a PointF^
are different kinds of things, they are both described by the same Type
object. The system generally decides which kind of thing a Type
represents based upon how the type is used. If the PointF
type is used to describe a storage location, that storage location will be allocated to hold a structure. The C++/CLI compiler can allow the declaration of a PointF^
variable, but the Framework has no concept of such a thing. Within C++/CLI code, the compiler can use a storage location of type Object
to hold reference to a PointF
heap object, or it can use an Object[]
to hold a bunch of such references; if such locations are never exposed to the outside world and the compiler never stores anything but PointF
references, the compiler can know the target of any non-null reference may be safely used as a PointF
. The compiler can't expose such storage locations to outside code, however, because the type system offers no means of indicating that other code should be limited to storing PointF
references.
回答4:
As others have mentioned, generic types only accept CLS-compliant type parameters. Since PointF^
is not CLS-compliant, List<PointF^>
is invalid. array<>
avoids this issue by being a template type, not a generic type.
However, there is a (fairly easy) workaround: create a List<Nullable<PointF>>
. Your sample program then becomes:
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;
}
来源:https://stackoverflow.com/questions/1558620/c-cli-boxing-and-generic-lists