3

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 PointFs?

4

4 回答 4

5

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.

于 2009-10-24T01:29:54.430 回答
1

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;
}
于 2015-06-01T21:19:18.703 回答
0

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];
于 2009-10-13T07:54:16.180 回答
0

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.

于 2013-02-06T17:54:20.183 回答