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

本文关键字:类型 成员 泛型 访问 | 更新日期: 2023-09-27 18:28:55

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

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

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

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

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

不,不会-如果使用泛型类型约束,生成的IL将而不是box/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

只要您坚持使用泛型类型参数,就应该可以了。

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

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

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

注意:正如@Jon指出的那样,通用约束不会框住值类型。