I have the following code for C++, in a templated class that represents a point. I would like to translate it into C#:
template <class T>
class Point
{
public:
T x;
T y;
T z;
template<typename U> explicit Point(const Point<U> &p)
: x((T)p.x), y((T)p.y), z((T)p.z)
{
}
}
This code enables a point of a given type to be explicitly cast into a point of another type. For example, you may use it something like (admittedly I am not 100% sure on the syntax here, but I get the concept):
Point<float> p;
Point<int> q = (Point<int>)p;
How could I enable the equivalent to this in C#? So far I have:
public class Point<T>
{
public T X { get; set; }
public T Y { get; set; }
public T Z { get; set; }
// Constructors exist that accept X, Y, and Z as parameters
public static explicit operator Point<U>(Point<T> p)
{
}
}
This gives an error, however, saying "U" is undefined. This makes sense... but how/where do I define U? Is my approach incorrect?
The difference between my question and the one here is that I am simply changing the underlaying type of the generic class via a cast... not trying to change one generic class into a different generic class with the same underlaying type.
I think the best you can get is this:
public class Point<T>
{
public T X { get; set; }
public T Y { get; set; }
public T Z { get; set; }
public Point<U> As<U>()
{
return new Point<U>()
{
X = Convert<U>(X),
Y = Convert<U>(Y),
Z = Convert<U>(Z)
};
}
static U Convert<U>(T t) => (U)System.Convert.ChangeType(t, typeof(U));
}
You cannot define a generic conversion operator, so you need it to be an explicit function. Moreover, a simple cast (U)t won't work, so you need Convert.ChangeType (which will work if your types are numeric).
Usage:
var p1 = new Point<int> { X = 1, Y = 2, Z = 3 };
var p2 = p1.As<double>();
(works as expected).
As far as I know, this kind of generic cast is only allowed in C# if there's some kind of inheritance relationship between T and U.
The closest equivalent would be to define a generic method for the conversion:
public Point<U> To<U>()
{
dynamic p = this;
return new Point<U>((U)p.X, (U)p.Y, (U)p.Z);
}
You cannot convert directly T to U as the compiler has no way to know whether it'll be safe. I use the dynamic keyword to bypass that restriction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With