我正在编写一个C#程序,它在几个坐标系中进行计算,并在它们之间进行转换。为了防止混淆,我想为每种坐标使用单独的静态值类型。例如:
struct FooSpaceCoords {
double x, y, z;
}
struct BarSpaceCoords {
double x, y, z;
}
现在一个方便且类型安全的矩阵类会很好。但以下情况不起作用:
public class MatrixTransform<To, From> where To : struct, From : struct
{
.... some implementation that requires .x, .y and .z ....
}
这失败了,因为编译器无法知道To
和From
有成员.x
,.y
&amp; .z
。
我可以定义一个IHaveXYZ
界面,但在我看来,这会导致许多拳击操作违背整个计划的精神(并且如果重要的话效果较差)。
有一种简单的方法可以做我原本想要的吗?
答案 0 :(得分:3)
我可以定义一个IHaveXYZ界面,但在我看来,这会导致许多拳击操作违背整个计划的精神(并且如果重要的话效果较差)。
不,它不会 - 如果您使用泛型类型约束,生成的IL将不框/ unbox。例如:
interface IFoo
{
void Foo();
}
struct Bar : IFoo
{
public void Foo()
{
// Do something
}
}
class Test
{
static void DoFoo<T>(T value) where T : IFoo
{
value.Foo();
}
static void Main()
{
Bar bar = new Bar();
DoFoo(bar); // No boxing involved
}
}
DoFoo
的IL如下所示:
.method private hidebysig static void DoFoo<(IFoo) T>(!!T 'value') cil managed
{
// Code size 16 (0x10)
.maxstack 8
IL_0000: nop
IL_0001: ldarga.s 'value'
IL_0003: constrained. !!T
IL_0009: callvirt instance void IFoo::Foo()
IL_000e: nop
IL_000f: ret
} // end of method Test::DoFoo
注意“约束”部分。来自ECMA-335第I.8.2.4节:
通用参数的装箱和拆箱会增加CLI实施的性能开销。
constrained.
前缀可以通过避免装箱值类型,在虚拟调度到值类型定义的方法时提高性能。
重要的是,不只是将value
称为IFoo
。这行将包装该值(当T
为值类型时):
IFoo copy = value; // Might box
只要您坚持使用泛型类型参数,就应该没问题。
答案 1 :(得分:1)
为两个结构实现公共接口,并将字段更改为属性。
interface ISomething
{
Double X{ get;}
Double Y{ get;}
Double Z{ get;}
}
然后将此接口添加为通用约束。你已经完成了
注意:因为@Jon指向泛型约束不会包含值类型。