C#中返回类型前的ref关键字是什么意思

2023-11-30

下面的代码中,什么意思ref in the GetAge()方法签名?

public class Person
{
    private int age;
    public ref int GetAge()
    {
        return ref this.age;
    }
}

The refreturn 是 C# 7.0 中的新功能。它允许返回对内存位置的引用。这在以前的 C# 版本中是不可能的。您甚至可以像这样存储返回的内存位置:

var person = new Person();

// Here we can store the reference to the memory area and we can modify it
ref int age = ref person.GetAge();

// like this
age = 50;

整个过程中我们都在同一个内存位置上工作,而不是在同一个内存位置上工作。copy of the age.


幕后发生了什么?

如果我们有这样的代码:

public class Program
{
    public static void Main()
    {
        var person = new Person();

        // Here we can store the reference to the memory area and we can modify it
        ref int age = ref person.GetAge();

        // like this
        age = 50;
    }
}

public class Person
{
    private int age;
    public ref int GetAge()
    {
        return ref this.age;
    }
}

以下是编译器 (Roslyn) 在幕后对该代码执行的操作:

using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
[assembly: AssemblyVersion("0.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[module: UnverifiableCode]
public class Program
{
    public unsafe static void Main()
    {
        Person person = new Person();
        int* age = person.GetAge();
        *age = 50;
    }
}
public class Person
{
    private int age;
    public unsafe int* GetAge()
    {
        return ref this.age;
    }
}

好的!!!我想我们都很高兴我们不必处理所有这些*恶作剧。


这个功能什么时候有用?

添加 ref 局部变量和 ref 返回可以避免复制值或多次执行解引用操作,从而提高算法的效率。

当您使用值类型的大型数据结构时,它最有用(struct)并且将副本传入和传出方法可能不是很有效。例如,假设我们有一个类,其中包含一堆struct对象:

class Container
{
    private Tile[] tiles = new Tile[] { new Tile { X = 10 } };

    public Tile this[int x]
    {
        get { return tiles[x]; }
        set { tiles[x] = value; }
    }
}

public struct Tile
{
    public int X { get; set; }
    // Many more propeties
}

如果我们想与Tile对象,因为它们是struct,我们将无法这样做:

var container = new Container();
container[0].X = 10;

我们不能这样做,因为编译器会发出以下错误:

错误CS1612无法修改“Container.this[int]”的返回值,因为它不是变量

编译器抛出该错误是为了明确表明您认为自己正在做的事情(修改索引项)实际上并不是您正在做的事情。您实际上正在修改副本,因此它迫使您这样做。因此,为了能够设置 X,您需要在副本上进行如下操作:

var container = new Container();
var copy = container[0];
copy.X = 10;

// now we need to set the item to the copy
container[0] = copy;

正如您所看到的,这不是很有效,特别是当我们与大型企业合作时struct我们需要以迭代的方式操纵其中许多。

使用 C# 7.0,我们可以这样做:

public ref Tile this[int x]
{
    get { return ref tiles[x]; }
}

现在我们可以操纵Tile直接进行,无需发送副本、制作副本,然后将原始项目设置为副本。像这样:

var container = new Container();
ref Tile tile = ref container[0];  
tile.X = 10;  

一个小问题

网上有很多例子,它们的语法如下:

// Notice the ref missing on the right side
ref int age = person.GetAge();

这将导致此错误:

无法使用值初始化按引用变量

正确的语法是ref两边都是这样的:

ref int age = ref person.GetAge();

更多信息

Here是一个 SO 问题,其中已经讨论了此功能。我想这个问题现在是history. And here是 Eric Lippert 撰写的关于此功能的另一篇文章。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#中返回类型前的ref关键字是什么意思 的相关文章

  • Java 中的 TreeSet 与 C#.net 的等效项

    我有 Java 代码 其中包含TreeSet 我想将代码转换为 C 我可以使用哪个等效集合 如果没有 请提出替代方案 那将是系统 集合 通用 SortedSet
  • 无捕获 lambda 是结构类型吗?

    P1907R1 http www open std org jtc1 sc22 wg21 docs papers 2019 p1907r1 html 接受 C 20 引入结构类型 它们是非类型模板参数的有效类型 GCC 和 Clang 都接
  • TPL Dataflow如何删除块之间的链接

    我想知道 如何删除块之间的链接 换句话说 我想要与 LinkTo 相反 我想写一个基于 tlp 数据流的记录器 我编写了这个接口 并希望在需要时删除 ILogListener 的订阅 public interface ILogManager
  • 从值获取键 - Dictionary>

    我无法通过指定值来获取密钥 我实现这一目标的最佳方法是什么 var st1 new List
  • 未定义的参考错误 - rand

    我正在创建一个命令行 C 测试应用程序 可执行 以便在我的 root Android 设备上运行 该可执行文件使用多个预构建的 C 库 其中之一使用 rand 在链接状态期间我收到错误 rand 的未定义引用 为了检查路径是否设置正确 我尝
  • 如何从 C# 可移植类库 (PCL) 添加对 F# 可移植库的引用

    我有一个项目 其中包含两个 F 项目和一个 C 项目 我想在其中编写一些 XUnit 测试 FS PL F 3 1 3 3 1 0 可移植库 FS PL Legacy F 31 2 3 5 1 可移植库 旧版 测试 C NET 4 5 Wi
  • 如何在 VS 2013 的立即窗口中执行 LINQ 和/或 foreach?

    在调试过程中探测当前状态时 立即窗口是非常有用的工具 我了解到 通过使用问号 人们可以在那里做更多的事情 如图所示在这篇文章中 https stackoverflow com questions 32934635 execute metho
  • 未构建 csproj 时抑制 AfterBuild 目标

    我在 MSBuild 中有一个构建后目标来复制一些构建输出 这是 linkedin 作为对AfterBuild目标 暴露于Microsoft CSharp targets
  • 隐藏树视图列表中的节点。在 C# 中

    我正在使用 VS 2005 C 正在处理一个未完成的 WinForm 我已将 XML 解析为树视图列表 但遇到了一些问题 我想知道是否有一种方法可以隐藏 过滤 删除名称中包含 this text 的某个节点 而不必依赖文本框 这就是我对这个
  • 不屈不挠的野兽:一个二维字符数组,位于结构内部,位于非托管 dll 的内部

    我束紧腰 冒险进入了遗产之地 砍倒 召唤并集结了各种野兽 现在我站在了一个如此凶猛的生物面前 据我对我的弟兄们进行的详尽调查来看 我现在所面对的生物是如此凶猛 武器中 没有一个代码战士能够幸存 以下是详细信息 我试图将结构内部的二维字符数组
  • 为什么 ATOMIC_FLAG_INIT 为假?

    In C 11有std atomic flag这对于线程循环很有用 static std atomic flag s done ATOMIC FLAG INIT void ThreadMain while s done test and s
  • 为什么编译器不对同一翻译单元中的 ODR 违规发出警告

    在同一个翻译单元中 ODR 问题很容易诊断 那么为什么编译器不会针对同一翻译单元中的 ODR 违规发出警告呢 例如在下面的代码中https wandbox org permlink I0iyGdyw9ynRgny6 https wandbo
  • “应用程序配置”文件中的最大键/值长度

    允许的最大长度是多少MyKey and MyValue在配置文件中
  • const int 列表而不是 enum

    我开始研究大型 C 代码库 并发现使用带有多个 const ints 字段的静态类 这个类的行为与枚举完全一样 我想将类转换为实际的枚举 但权力被拒绝 我想转换它的主要原因是这样我可以将枚举作为数据类型而不是 int 这对可读性有很大帮助
  • 当 MSB 位等于 0 时如何以十六进制格式打印它们

    我需要使用打印变量HEX格式 问题是当我的变量很小时 MSB 等于 0 因此不会打印它们 ex uint16 t var 10 0x000A h gt 我需要打印 000A 但无论我做什么它总是打印 A 我怎样才能让它发挥作用 您可以添加前
  • DateTimeFormat.AbbreviatedMonthNames 在月份名称末尾添加一个点

    昨晚 我们将 Web 服务层从物理 Windows 2008 r2 迁移到虚拟 Windows 2012 我们的日志中收到大量有关 DateTime 无效格式的事件 这很奇怪 因为我们仔细检查了区域设置 长话短说 CultureInfo G
  • CGAL:如何有效计算多面体的面面积?

    我有一个多面体 其面是三角形 我知道在 CGAL 中 Triangle 3 类提供了 squared area 方法 通过它我们可以计算三角形的面积 有什么方法可以将其应用到多面体方面吗 或者关于如何计算每个面的面积有什么想法吗 这是一个例
  • 从多页 tiff 中提取帧 - C#

    有一个多页 tiff 我想从此 Tiff 文件中提取第 n 页 帧 n 并保存它 如果我的多页 tiff 有 3 帧 在我提取一页 帧后 我想留下 1 张图像有 2 页 帧 并且 1 张图像只有 1 页 帧 下面是一些代码 用于将多帧 ti
  • ASP .NET Core IIS 托管用户身份名称为空且 IsAuthenticated=false

    我在 IIS 上运行 ASP NET Core dll 使用 AspNetCoreModule 使用以前的 ASP NET 我可以通过以下方式获取用户身份名称 HttpContext Current User Identity Name 因
  • 同时运行 x 个网络请求

    我们公司有一个网络服务 我想通过我自己的服务发送 XML 文件 存储在我的驱动器上 HTTPWebRequestC 中的客户端 这已经有效了 Web服务同时支持5个同步请求 一旦服务器上的处理完成 我就会从Web服务获得响应 每个请求的处理

随机推荐