C# 13 新的Ref Struct Interfaces

C# 13 Ref Struct Interfaces

Intro

C# 从 7.2 开始引入了 ref structref struct 只能分配在栈上,不能被装箱,因为不能被装箱之前的版本中 ref struct 是不能实现接口的,在转成接口的时候会导致发生装箱,这是不被允许的,而我们在做一些设计的时候往往会使用到接口,用接口定义契约 contract,C# 13 开始我们可以允许 ref struct 实现接口,并且增加了可以作为泛型类型约束允许 ref struct 类型

Sample

来看一个简单的示例:

file interface IAge
{
    public int GetAge();
}

file ref struct Age : IAge
{
    public int GetAge() => 1;
}

使用的地方需要这样用:

private static void PrintAge<TAge>(TAge age)
    where TAge : IAge, allows ref struct
{
    Console.WriteLine(age.GetAge());
}

方法需要声明为泛型参数,并且要指定泛型约束 allows ref struct

我们不能直接声明参数为对应的接口类型,如 IAge,这会导致 ref struct 被装箱,编译器会报错,例如我们这样定义,调用的时候编译器就会报错,这也意味着 ref struct 不能使用接口默认实现方法,因为接口默认实现方法需要转成接口才能使用,而转接口就意味着要发生装箱,对于 ref struct 来说是不被允许的

CS1503: Argument 1: cannot convert from 'CSharp13Samples.RefStructAge' to 'CSharp13Samples.IAge'

private static void PrintAge0(IAge age)
{
    Console.WriteLine(age.GetAge());
}

4cd9983636e7fd8c04fa520eb5746525.png

CS1503 error

另外需要显式声明 allows ref struct 默认是不允许将 ref struct 用作泛型类型参数的,不声明也会导致编译器报错

CS9244: The type 'RefStructAge' may not be a ref struct or a type parameter allowing ref structs in order to use it as parameter 'TAge' in the generic type or method 'RefStructInterfaceSample.PrintAge(TAge)'

1481047e2079241baeb1f98403f09db5.png

CS9244-error

除了方法我们也可以声明 Property

internal interface IAge
{
    int AgeNum { get; }
    int GetAge();
}

internal ref struct RefStructAge : IAge
{
    public int AgeNum => 1;

    public int GetAge() => AgeNum;
}

如果接口里有定义默认实现方法,在定义 ref struct 的时候就会报错

95393173a82f54c970e7be4113a881c2.png

Interface default implemented method

More

这一特性可以有助于避免 struct 被装箱导致性能问题,可以更好地利用 ref struct 带来的性能改进和编译器的约束检查

可以实现接口也有有助于在设计前面更加专注在更核心的接口设计上无需关心实现方式,实现的时候选择基于 class 实现也可以基于 ref struct 来实现, dotnet runtime 的一些 library 里的泛型参数也新增支持了这一特性,例如:https://github.com/dotnet/runtime/issues/102671

9f08cc24d5dafc1763ccb097c3dff1ab.png

library-ref-struct

后续的 runtime library 应该也会基于这一特性优化一些原来基于 class 的实现,转而使用基于 ref struct 的实现来优化性能

对前面的示例做一个简单的 benchmark

6c419364a6077be13372eb7508385e92.png

35af42f77b917a562d9112105fc3afb6.png

2c3757d55bb94bc36b060e4751bebfa2.png

References

  • https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history#c-version-72

  • https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/ref-struct

  • https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/structs#1623-ref-modifier

  • https://github.com/dotnet/csharplang/blob/main/proposals/csharp-13.0/ref-struct-interfaces.md

  • https://github.com/dotnet/csharplang/issues/7608

  • https://github.com/WeihanLi/SamplesInPractice/blob/main/net9sample/CSharp13Samples/RefStructInterfaceSample.cs

  • https://github.com/dotnet/runtime/issues/102671

  • https://github.com/dotnet/runtime/issues/105276

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值