我经常遇到这个问题:我喜欢为不同的返回类型重载一些具有相同参数的方法,但.NET拒绝对密封类/基元的通用约束。我将此模式称为phantom generics
。
where
语句后面的类型中。
这是我的代码:
public static class Reinterpret {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe float Cast<T>(int value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((float*)&value); //reinterpret the bytes of 'value' to a float
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe float Cast<T>(uint value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((float*)&value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe double Cast<T>(long value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((double*)&value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe double Cast<T>(ulong value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((double*)&value);
}
}
答案 0 :(得分:7)
这是一种略微不同的接近方式:
// Constraints just to be vaguely reasonable.
public static class Reinterpret<T> where T : struct, IComparable<T>
{
public T Cast(int value) { ... }
public T Cast(uint value) { ... }
public T Cast(float value) { ... }
public T Cast(double value) { ... }
// etc
}
对于实现,您可以只有Func<int, T>
字段,Func<double, T>
字段等,然后有一个很大的静态构造函数:
static Reinterpret()
{
if (typeof(T) == typeof(int))
{
// Assign all the fields using lambda expressions for ints.
// The actual assignment might be tricky, however - you may
// need to resort to some ghastly casting, e.g.
castDouble = (Func<double, T>)(Delegate)(Func<double, int>)
x => *((double*)&value;
}
....
}
然后,对于您不想支持的任何类型,字段将为null。每个Cast
方法都如下所示:
if (castIntMethod != null)
{
return castInt(value);
}
throw new InvalidOperationException("...");
说实话,这不是我真正想做的事情。我通常只使用BitConverter
。但它是选项。
答案 1 :(得分:6)
泛型不是模板。它们不像模板那样。它们不能像模板一样。
“幻影”通用参数无法帮助您模拟模板(并且reinterpret_cast
不是真正的模板,无论如何),因为您很快就会遇到泛型不会支持专业化。
特别是,你问过“有没有办法在泛型中使用显式类型来保持方法的独特性?”并评论说“通用约束......保持[原文如此不同的方法”。但他们实际上并没有。这些方法之所以不同,只是因为参数类型不同。泛型是根据重载计算的,它们不会影响重载。