在C#中访问泛型值类型的成员

时间:2013-08-24 09:25:56

标签: c# generics coordinate-systems

我正在编写一个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 ....
 }

这失败了,因为编译器无法知道ToFrom有成员.x.y&amp; .z

我可以定义一个IHaveXYZ界面,但在我看来,这会导致许多拳击操作违背整个计划的精神(并且如果重要的话效果较差)。

有一种简单的方法可以做我原本想要的吗?

2 个答案:

答案 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指向泛型约束不会包含值类型。