[译]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>和统一内存管理 (完)
[译]C# 7系列,Part 9: ref structs ref结构的更多相关文章
- [译]C# 7系列,Part 1: Value Tuples 值元组
Mark Zhou写了很不错的一系列介绍C# 7的文章,虽然是2年多年前发布的,不过对于不熟悉C# 7特性的同学来说,仍然有很高的阅读价值. 原文:https://blogs.msdn.microso ...
- [译]C# 7系列,Part 6: Read-only structs 只读结构
原文:https://blogs.msdn.microsoft.com/mazhou/2017/11/21/c-7-series-part-6-read-only-structs/ 背景 在.NET世 ...
- [译]C# 7系列,Part 7: ref Returns ref返回结果
原文:https://blogs.msdn.microsoft.com/mazhou/2017/12/12/c-7-series-part-7-ref-returns/ 背景 有两种方法可以将一个值传 ...
- [译]C# 7系列,Part 8: in Parameters in参数
原文:https://blogs.msdn.microsoft.com/mazhou/2018/01/08/c-7-series-part-8-in-parameters/ 背景 默认情况下,方法参数 ...
- [译]C# 7系列,Part 2: Async Main 异步Main方法
原文:https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main/ 你大概知道,C#语言可以构建两种 ...
- [译]C# 7系列,Part 3: Default Literals 默认文本表达式
原文:https://blogs.msdn.microsoft.com/mazhou/2017/06/06/c-7-series-part-3-default-literals/ C#的default ...
- [译]C# 7系列,Part 4: Discards 弃元
原文:https://blogs.msdn.microsoft.com/mazhou/2017/06/27/c-7-series-part-4-discards/ 有时我们想要忽略一个方法返回的值,特 ...
- [译]C# 7系列,Part 5: private protected 访问修饰符
原文:https://blogs.msdn.microsoft.com/mazhou/2017/10/05/c-7-series-part-5-private-protected/ C#有几个可访问性 ...
- [译]C# 7系列,Part 10: Span<T> and universal memory management Span<T>和统一内存管理
原文:https://blogs.msdn.microsoft.com/mazhou/2018/03/25/c-7-series-part-10-spant-and-universal-memory- ...
随机推荐
- 微信中使用popup等弹窗组件时点击输入框input键盘弹起导致IOS中按钮无效处理办法
因为在IOS微信中在弹窗中使用input使键盘弹起,使弹窗的位置上移,当键盘关闭时页面还在上面,弹窗位移量也在上面,只有下拉才能回到原位,这样弹窗也消失了.我的处理办法就是在键盘弹起和消失的时候,让页 ...
- MyBaits框架入门总结
MBaits简介 联系方式:18873247271(微信同步) 廖先生 qq:1727292697 MyBatis的前身叫iBatis,本是apache的一个开源项目, 2010年这个项目由apach ...
- Python 并发总结,多线程,多进程,异步IO
1 测量函数运行时间 import time def profile(func): def wrapper(*args, **kwargs): import time start = time.tim ...
- Linux LVM 配置
本文出自 “www.kisspuppet.com” 博客,请务必保留此出处http://dreamfire.blog.51cto.com/418026/1084729 许多Linux使用者安装操作系统 ...
- Java通过 Scanner 类来获取用户的输入
通过 Scanner 类来获取用户的输入. import java.util.Scanner; Scanner s = new Scanner(System.in);// 从键盘接收数据 Syste ...
- 【Android - IPC】之Messenger简介
参考资料: 1.<Android开发艺术探索>第二章2.4.3 2.[Messenger完全解析] 1.Messenger概述 Messenger,译为“信使”,是Android中一种基于 ...
- PAT甲级专题|链表
PAT链表专题 关于PAT甲级的链表问题,主要内容 就是"建立链表" 所以第一步学会模拟链表,pat又不卡时间,这里用vector + 结构体,更简洁 模拟链表的普遍代码 cons ...
- 从UI设计转向前端的艰辛过程,从背单词开始。。。
很纠结到底是继续做UI设计还是转行前端呢?从刚开始的害怕代码到接触代码又喜欢代码的过程,我在想我是不是太飘了,我感觉我做事就是三分钟热度.我感觉学前端对我最大的阻碍就是英语单词了,10个单词里面最起码 ...
- 华为参与《基于5G技术的医院网络建设标准》的制定
[摘要] 5G 千兆网承载五地远程会诊,现场完成三例复杂性疑难重症远程病例讨论 [中国,北京,2019年9月4日] 金秋之际,在国家卫生健康委指导下,由中日友好医院•国家远程医疗与互联网医学中心•国家 ...
- hibernate查询方式(二)
1.HQL查询(hibernate query language) 操作的是实体类和属性 *查询所有记录 //1.hql查询操作会使用Query对象 // (1)写sql语句 创建Query对象, S ...