3

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

我可以定义一个IHaveXYZ接口,但在我看来,这将导致大量的拳击操作违背整个计划的精神(并且效率较低,如果这很重要的话)。

有没有一种简单的方法可以做我最初想做的事情?

4

2 回答 2

3

我可以定义一个 IHaveXYZ 接口,但在我看来,这将导致大量的装箱操作,这违背了整个计划的精神(并且效率较低,如果这很重要的话)。

不,它不会 - 如果您使用泛型类型约束,生成的 IL 将不会装箱/拆箱。例如:

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
    }
}

IL forDoFoo看起来像这样:

.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

只要你坚持泛型类型参数,你应该没问题。

于 2013-08-24T09:32:59.537 回答
1

为结构实现一个通用接口并将字段更改为属性。

interface ISomething
{
    Double X{ get;}
    Double Y{ get;}
    Double Z{ get;}
}

然后将此接口添加为通用约束。你完成了

注意:正如@Jon 指出的通用约束不会将值类型装箱。

于 2013-08-24T09:31:36.173 回答