[英]Explicit Casting Generic to Another Type in C#
I have the following code for C++, in a templated class that represents a point.我有以下 C++ 代码,在一个表示点的模板化类中。 I would like to translate it into C#:
我想把它翻译成 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):
例如,您可以使用它类似的东西(不可否认,我对这里的语法不是 100% 确定,但我明白了这个概念):
Point<float> p;
Point<int> q = (Point<int>)p;
How could I enable the equivalent to this in C#?如何在 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.但是,这会产生错误,说“U”未定义。 This makes sense... but how/where do I define U?
这是有道理的......但是我如何/在哪里定义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).此外,简单的强制转换
(U)t
不起作用,因此您需要Convert.ChangeType
(如果您的类型是数字,它会起作用)。
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
.据我所知,只有在
T
和U
之间存在某种继承关系时,才允许在 C# 中使用这种泛型转换。
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.您不能直接将
T
转换为U
因为编译器无法知道它是否安全。 I use the dynamic
keyword to bypass that restriction.我使用
dynamic
关键字绕过该限制。
Similar to Kevin's answer , but without dynamic
is to use a double cast:类似于凯文的回答,但没有
dynamic
是使用双重演员:
public Point<U> To<U>()
{
return new Point<U>((U)(object)X, (U)(object)Y, (U)(object)Z);
}
Both of our answers don't catch any issues at compile-time.我们的两个答案在编译时都没有发现任何问题。
You cannot declare operators with additional generic type arguments, but you can declare ones to or from specific generic types like Point<int>
.您不能使用额外的泛型类型参数声明运算符,但您可以向或来自特定泛型类型(如
Point<int>
声明运算符。 C# will also not let you perform arbitrary conversions by casting from or to T
. C# 也不会让您通过从或到
T
进行任意转换来执行任意转换。
The least boilerplate heavy option that maintains a modicum of type safety would be to constrain the T
parameter to IConvertible
:保持少量类型安全的最少样板重选项是将
T
参数限制为IConvertible
:
public class Point<T> where T : IConvertible
{
// ...
public static explicit operator Point<int>(Point<T> point)
{
// The IFormatProvider parameter has no effect on purely numeric conversions
return new Point<int>(point.X.ToInt32(null), point.Y.ToInt32(null), point.Y.ToInt32(null));
}
}
However, this will not prevent users from declaring nonsensical, unsupported types such as Point<DateTime>
which will then throw at runtime when attempting a conversion.但是,这不会阻止用户声明无意义的、不受支持的类型,例如
Point<DateTime>
,然后在尝试转换时会在运行时抛出。
You cannot define additional generic type constraints, but you can do something like this, using operators and methods.你不能定义额外的泛型类型约束,但你可以使用运算符和方法来做这样的事情。
public class Point<T>
{
public T X { get; set; }
public T Y { get; set; }
public T Z { get; set; }
public static explicit operator Point<T>(Point<int> v)
{
return v.As<T>();
}
public static explicit operator Point<T>(Point<double> v)
{
return v.As<T>();
}
public static explicit operator Point<T>(Point<float> v)
{
return v.As<T>();
}
public Point<TU> As<TU>()
{
return new Point<TU>()
{
X = ConvertTo<TU>(X),
Y = ConvertTo<TU>(Y),
Z = ConvertTo<TU>(Z)
};
}
private static TU ConvertTo<TU>(T t)
{
return (TU) Convert.ChangeType(t, typeof(TU));
}
}
Usage:用法:
Point<double> d = new Point<double>()
{
X = 10d, Y = 10d, Z = 10d
};
Point<int> i = (Point<int>) d;
Point<float> f = (Point<float>) i;
d = (Point<double>) f;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.