指针是一个变量,它指向另一个变量的地址。 换句话说,指针保存另一个变量的存储地址或存储位置。 直到最近,在C#中使用指针的唯一方法是使用不安全的代码。 您可以利用unsafe
关键字定义不安全的上下文,然后创建非托管的指针或使用非托管的指针调用本机函数。
在此应注意,不安全代码表示在CLR上下文之外执行的代码。 它是非托管代码。 但是,由于默认情况下关闭了CLR提供的安全性,因此建议仅在知道.Net中内存管理的工作方式时才使用不安全的代码。
C#中的对象引用是指向对象开头的类型安全指针。 CLR中还有另一种类型的指针,称为托管指针。 本文研究什么是托管指针,为什么有用,以及如何在C#中使用它们。
C#中的托管指针介绍
托管指针与类型安全指针的不同之处在于,它可以指向对象的其他位置,即不仅指向对象的开头。 像对象引用一样,托管指针可以指向存储在托管堆中的对象。 区别在于,虽然对象引用指向对象的开头,但是托管指针可以指向方法参数,字段,数组元素或对象的任何其他部分。
本质上,托管指针可以指向以下内容:
- 局部变量
- 数组的元素
- 方法参数
- 复合类型的字段
托管指针不直接支持指针算法。 您不能“添加”或“减去”它们指向的地址值。 您不能装箱托管指针的值。 显然,由于这些限制,托管指针没有在C#语言中显式公开。 但是,很长一段时间以来,托管指针一直在C#中作为参考参数隐含。 当通过引用将参数传递给方法时,您将在幕后使用托管指针。
在C#中使用托管指针的10条规则
请注意托管指针的以下几点。
- 托管指针不能为null。
- 受管指针不可能指向另一个受管指针。
- 托管指针不能在堆上。
- 您不能将托管指针与对象引用互换。
- 您不能将托管指针存储在静态变量中或作为数组或字段的元素存储。
- 您不能将托管指针用作数组的元素类型。
- 托管指针可以指向对象引用或值类型。
- 如果将方法参数作为引用传递,则该参数实际上是托管指针。
- 托管指针也称为byref类型。
- 托管指针可以指向方法的局部变量或方法的参数。
在C#中通过引用传递参数
好的,我们已经受够了这些概念。 现在让我们编写一些代码来了解托管指针。 您可以使用ref参数,ref局部变量或ref返回来表示托管指针。 让我们逐一探讨这些内容。
考虑以下仅包含一个成员(整数变量)的结构。
public struct MyStruct
{
public int MyField;
}
下面的方法更新MyStruct实例的MyField数据成员的值。
private static void Update(ref MyStruct data)
{
data.MyField = 5;
}
以下代码段说明了如何通过引用而不是值来传递参数。
public int Main()
{
MyStruct obj = new MyStruct();
obj.MyField = 1;
Update(ref obj);
Console.WriteLine(obj.MyField);
Console.Read();
}
您可以利用结构代替类来避免堆分配和复制数据的开销。 这是一个很好的优化技巧,可用于数据成员很少的结构。
当您执行上述程序时,控制台窗口中将显示“ 5”。
使用ref本地将托管指针存储在C#中
您还可以使用本地的ref来存储托管指针。 以下代码段说明了如何实现此目的。 注意在分配的两侧都使用了ref关键字。
public static void UpdateDataUsingRefLocal(MyStruct data)
{
ref int refLocal = ref data.MyField;
refLocal = 10;
}
您可以利用ref return从代表托管指针的方法返回变量。 请注意,这不能是局部变量,即您不能返回代表托管指针的局部变量。 尝试返回局部变量将导致编译错误。
以下代码段说明了如何使用ref返回。
public static ref int GetMarksByRef(int[] marks, int subjectIndex)
{
return ref marks[subjectIndex];
}
对象引用指向对象的开头,而托管指针可以指向对象内部,类型的字段或数组的元素。 知道托管指针如何在后台工作很有趣。 我将在以后的文章中讨论托管指针的工作方式。
From: https://www.infoworld.com/article/3336022/how-to-use-managed-pointers-in-c.html