[译]C# 7系列,Part 9: ref structs ref结构
原文:https://blogs.msdn.microsoft.com/mazhou/2018/03/02/c-7-series-part-9-ref-structs/
背景
在之前的文章中,我解释了许多新的C#特性,每一个特性都是为了增强语言或者解决问题而引入的。具体来说,我解释了值类型和引用类型、按值传递参数、按引用传递参数、ref局部变量和ref返回结果以及in参数。这其中许多功能是为高性能场景设计的。
ref和in参数可以帮助避免复制值,从而减少内存分配。当你有分配在堆栈的局部变量作为方法的实际参数传递时,这么做是有效率的的,在这种情况下,所有的分配都在堆栈上;不需要堆分配。
对于高性能和原生开发场景,你可能希望“仅限堆栈”类型始终停留在执行堆栈上,因此对这种类型的对象的操作只能发生在堆栈上,在作用域中公开给托管堆的任何对这种类型的外部引用都应该被禁止。
ref结构
ref struct是仅在堆栈上的值类型:
- 表现一个顺序结构的布局;(译注:可以理解为连续内存)
- 只能在堆栈上使用。即用作方法参数和局部变量;
- 不能是类或正常结构的静态或实例成员;
- 不能是异步方法或lambda表达式的方法参数;
- 不能动态绑定、装箱、拆箱、包装或转换。
ref struct也被称为嵌入式引用。
示例
下面的代码定义了一个ref结构。
public ref struct MyRefStruct
{
public int MyIntValue1;
public int MyIntValue2; [EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj) => throw new NotSupportedException(); [EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => throw new NotSupportedException(); [EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString() => throw new NotSupportedException();
}
请注意,我已经覆盖了从System.Object继承的Equals、GetHashCode和ToString方法。因为ref结构不允许装箱,所以你将无法调用这两个(译注:原文两个,应该是三个)基方法。
你可以在方法参数或局部变量中使用MyRefStruct作为常规值类型,但不能在其他地方使用它。
你也可以创建只读ref结构,只需将readonly指令添加到ref结构声明中即可。
public readonly ref struct MyRefStruct
{
public readonly int MyIntValue1;
public readonly int MyIntValue2; public MyRefStruct(int value1, int value2)
{
this.MyIntValue1 = value1;
this.MyIntValue2 = value2;
} [EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj) => throw new NotSupportedException(); [EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => throw new NotSupportedException(); [EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString() => throw new NotSupportedException();
}
与常规只读结构一样,需要将所有实例字段/属性设置为只读。
元数据
ref结构在C# 7.2中可用。此功能需要编译器级别更改才能工作,以便与以前编译器生成的程序集向后兼容。编译器会为ref结构声明发出[Obsolete]和[IsByRefLike]特性。
如果任何旧的程序集引用了包含ref结构类型的库,[Obsolete]属性将影响并阻止代码编译。
下面是为上面的ref结构声明生成的IL。
.class public sequential ansi sealed beforefieldinit Demo.MyRefStruct
extends [System.Runtime]System.ValueType
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( )
.custom instance void [System.Runtime]System.ObsoleteAttribute::.ctor(string, bool) = (
6d
6e
6e 6f 6f
6e
6f 6e 6f 6f 6f 6d
6c 2e
)
.custom instance void [System.Runtime]System.Runtime.CompilerServices.IsReadOnlyAttribute::.ctor() = ( )
// Fields
.field public initonly int32 MyIntValue1
.field public initonly int32 MyIntValue2
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
int32 value1,
int32 value2
) cil managed
{
// Method begins at RVA 0x2090
// Code size 16 (0x10)
.maxstack
// (no C# code)
IL_0000: nop
// this.MyIntValue1 = value1;
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: stfld int32 Demo.MyRefStruct::MyIntValue1
// this.MyIntValue2 = value2;
IL_0008: ldarg.0
IL_0009: ldarg.2
IL_000a: stfld int32 Demo.MyRefStruct::MyIntValue2
// (no C# code)
IL_000f: ret
} // end of method MyRefStruct::.ctor
.method public hidebysig virtual
instance bool Equals (
object obj
) cil managed
{
// Method begins at RVA 0x20a1
// Code size 6 (0x6)
.maxstack
// throw new NotSupportedException();
IL_0000: newobj instance void [System.Runtime]System.NotSupportedException::.ctor()
// (no C# code)
IL_0005: throw
} // end of method MyRefStruct::Equals
.method public hidebysig virtual
instance int32 GetHashCode () cil managed
{
.custom instance void [System.Runtime]System.ComponentModel.EditorBrowsableAttribute::.ctor(valuetype [System.Runtime]System.ComponentModel.EditorBrowsableState) = ( )
// Method begins at RVA 0x20a8
// Code size 6 (0x6)
.maxstack
// throw new NotSupportedException();
IL_0000: newobj instance void [System.Runtime]System.NotSupportedException::.ctor()
// (no C# code)
IL_0005: throw
} // end of method MyRefStruct::GetHashCode
.method public hidebysig virtual
instance string ToString () cil managed
{
.custom instance void [System.Runtime]System.ComponentModel.EditorBrowsableAttribute::.ctor(valuetype [System.Runtime]System.ComponentModel.EditorBrowsableState) = ( )
// Method begins at RVA 0x20af
// Code size 6 (0x6)
.maxstack
// throw new NotSupportedException();
IL_0000: newobj instance void [System.Runtime]System.NotSupportedException::.ctor()
// (no C# code)
IL_0005: throw
} // end of method MyRefStruct::ToString
} // end of class Demo.MyRefStruct
Span<T>和Memory<T>
有了类ref类型的支持,现在就可以为所有连续内存访问提供统一的类型。System.Span<T>表示内存的连续空间,可用于执行堆栈、托管堆和非托管堆的通用内存操作。
下面是ReadOnlySpan<T>的一个简单用法,用于去掉字符串的开始的空格。
internal class Program
{
private static void Main(string[] args)
{
string text = " I am using C# 7.2 Span<T>!";
Console.WriteLine(TrimStart(text).ToArray());
} private static ReadOnlySpan<char> TrimStart(ReadOnlySpan<char> text)
{
if (text.IsEmpty)
{
return text;
} int i = ;
char c; while ((c = text[i]) == ' ')
{
i++;
} return text.Slice(i);
}
}
结论
C# 7.2为高性能场景添加了语言特性,并为低级别的原生开发和互操作性场景提供了效率。ref结构还可以与stackalloc、Span<T>、fixed buffers和Ranges(C# 7.3)一起用于生产力。
注意:要使用这个特性,需要Visual Studio 2017 15.5或更高版本。
系列文章:
- [译]C# 7系列,Part 1: Value Tuples 值元组
- [译]C# 7系列,Part 2: Async Main 异步Main方法
- [译]C# 7系列,Part 3: Default Literals 默认文本表达式
- [译]C# 7系列,Part 4: Discards 弃元
- [译]C# 7系列,Part 5: private protected 访问修饰符
- [译]C# 7系列,Part 6: Read-only structs 只读结构
- [译]C# 7系列,Part 7: ref Returns ref返回结果
- [译]C# 7系列,Part 8: in Parameters in参数
- [译]C# 7系列,Part 9: ref structs ref结构 (本文)
- [译]C# 7系列,Part 10: Span<T> and universal memory management Span<T>和统一内存管理 (完)
最新文章
- Ubuntu下通过SSH远程登录服务器的方法
- Windows Azure Storage (20) 使用Azure File实现共享文件夹
- Web.config配置详解
- asp.net页面生命周期的文章推荐
- 算法导论( FFT &; 自动机 &; 最优二叉搜索树 !!!)
- 关于JS的数据类型的一些见解
- UIImageView、UISlider、UISwitch、UIStepper、UISegmentControl
- css页面布局
- mongodb 2.6 window 安装启动服务
- InActon-日志分析(KPI)
- Hibernate学习笔记--------1.单表操作
- Ubuntu Server安全Webserver搭建流程
- 有意思的数学题:Trapping Rain Water
- Make a travel blog by Blogabond the theme of wordpress
- 通过wireshark学习Traceroute命令(UDP,ICMP协议)
- protobuf转json
- 项目中的导出(jxl插件)
- kibana研究
- 从软件测试转型到C#上位机程序员
- 11.纯 CSS 创作一个荧光脉冲 loader 特效
热门文章
- 手把手带你一键部署 Kubernetes + KubeSphere 至 Linux
- 【论文阅读】The Contextual Loss for Image Transformationwith Non-Aligned Data(ECCV2018 oral)
- 解决 bash cd too many arguments 报错
- 【Android - IPC】之Binder机制简介
- Java package 包的命名规范。
- mysql 插入string类型变量时候,需要注意的问题,妈的,害我想了好几个小时!!
- python元类深入解析
- 重启testjenkins的步骤
- Javascript实现百度API
- 移动端开发语言的未来的猜想#华为云&;#183;寻找黑马程序员#【华为云技术分享】