从 C# 中的函数返回只读引用
介绍
在本指南中,您将学习编写类型和内存安全代码的概念。使用 C# 1.0 版,开发人员可以通过引用将参数传递给方法。随着时间的推移和编程改变世界,新的挑战出现了,迫使 C# 添加了新功能。在 C# 7.0 版中,添加了两个非常重要的功能:可以声明对局部变量的引用,可以从方法中通过引用返回。
本指南将为您理解两种参数传递类型(即按值传递和按引用传递)奠定基础,并阐明什么是结构以及如何从方法或函数返回它们。
价值与参考
C# 中传递参数的主要类型有两种:引用和值。C# 还能够定义自定义类型,但这不在本指南的讨论范围内。值类型和引用类型由于其实现的性质而表现出不同的性能特征。值类型在内存方面没有任何开销,因为您可以存储在特定类型(如int、string或double)中的数据具有特定大小。引用类型有两个额外的字段,称为ObjectHearder和MethodTable。
ObjectHeader被 CLR 用于存储附加信息,它基本上是一个位掩码。MethodTable是指向方法表的指针,方法表是一组关于特定类型的元数据。从对象调用方法会使 CLR 跳转到方法表并获取方法实现的地址以执行调用。
结构
您可以在此处找到有关结构的更详细指南。目前,您需要知道的是,结构与类非常相似,但它们用于存储数据。只读结构有点不同,因为它们的字段只能在调用结构的构造函数时修改一次。此后,只读结构保持不变。本指南是关于只读引用的,因此只读结构不适用。
这是一个只读结构的示例:
public readonly struct Pandemic
{
public string virusName { get; }
public double infectRatio { get; }
public int initialCases { get; }
public double deathRate { get; }
public Pandemic(string name, double ratio, int cases, double rate)
{
virusName = name;
infectRatio = ratio;
initialCases = cases;
deathRate = rate;
}
}
我们看到访问器仅用get定义,缺少set ,并且readonly关键字用于告诉 CLR 该结构将是不可变的。这意味着随着时间的推移,字段无法更改。
现在,您需要结合结构和通过引用传递值来为指南的原始主题创建演示。
Ref 只读
ref关键字向函数指示该值是通过引用传递的。它可以在多种情况下使用。例如,它可以用于方法签名和方法调用中,以将参数传递给方法。或者它可以用于方法签名中,以通过引用将值返回给调用者,这正是此时所需要的。此关键字允许您通知调用者返回的对象是不可变的,并且无法修改该值。
在深入研究只读结构之前,先看一下这个简单的例子:
using System;
namespace Pluralsight
{
public class SimpleRefReadonly
{
static int[] a = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
static ref int GetIndex(int index) {
return ref a[index];
}
public static void Main()
{
Console.WriteLine(GetIndex(0));
Console.ReadKey();
}
}
}
此代码有一个大小为 10 的静态整数数组。这里使用的方法GetIndex将索引作为参数并返回数组中的一项,该项是只读的。如果传递的索引大于数组的长度或小于零,您将收到一个异常,指出运行时发生了System.IndexOutOfRangeException异常。
举一个更复杂的例子,您可以构建一个结构体来表示一所学校,其中包含具有名称和大小的房间。一旦初始化,该结构体就不能允许修改房间的大小。
using System;
namespace Pluralsight
{
public struct ClassRooms {
public ClassRooms(string name, int size) {
Name = name;
Size = size;
_currentUtilization = null;
}
private ClassRooms[] _currentUtilization;
public string Name { get; set; }
public int Size { get; set; }
public override string ToString()
{
return $"{this.Name} :: {this.Size}";
}
public void SetRoom(ClassRooms[] classrooms) => _currentUtilization = classrooms;
public ref readonly ClassRooms Getutilization(int x)
{
return ref _currentUtilization[x];
}
}
public class ComplexRefReadonly
{
public static void Main()
{
var Rooms = new ClassRooms[] { new ClassRooms("Mathematics", 20), new ClassRooms("Biologs", 15) };
var School = new ClassRooms();
School.SetRoom(Rooms);
Console.WriteLine(School.Getutilization(1));
Console.WriteLine(School.Getutilization(0));
Console.ReadKey();
}
}
}
执行示例后,控制台上应该显示以下内容:
Biologs :: 15
Mathematics :: 20
这里有一个名为ClassRooms的结构体,它代表学校。此结构体不是只读的!每个教室都有一个名称和一个大小,需要传递给构造函数。ToString ()函数已被重写,以便每个教室的打印更漂亮。这里的关键是以下函数:
public ref readonly ClassRooms Getutilization(int x)
{
return ref _currentUtilization[x];
}
此函数返回特定教室的只读副本,不做任何修改,并保护初始化期间分配的原始值。Main ()函数负责建立学校;首先初始化Rooms变量数组,然后初始化由房间组成的School 。最后, Getutilization(<index>)函数允许检索给定教室的只读副本。
结论
在本指南中,我们讨论了值类型和引用类型之间的区别。我们阐明了ref readonly在概念上的含义,并在整个代码演示中展示了如何将它们结合起来以创建类型和内存安全的应用程序。我希望本指南对您有所帮助,并感谢您阅读它!
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~