为什么 C# 结构体方法不能返回对字段的引用,但非成员方法可以?

2024-04-17

以下是结构体实例方法尝试将只读引用返回到结构体实例字段的示例:

struct Foo
{
    internal int _x;

    public ref readonly int MemberGetX() => ref _x;
    //                                          ^^^
    // Error CS8170: Struct members cannot return 'this' or other instance members by reference
}

这会产生错误 CS8170结构成员不能通过引用返回“this”或其他实例成员。但是,使用扩展方法执行相同的操作不会产生错误:

static class FooExtensions
{
    public static ref readonly int ExtensionGetX( this in Foo foo )
    {
        return ref foo._x;
    }
}

相关问题的答案为什么 C# 结构不能返回对其成员字段的引用? https://stackoverflow.com/questions/49188391/why-cant-a-c-sharp-structure-return-a-reference-to-its-member-field讨论该语言不允许第一种情况的原因,但考虑到这些原因,我不清楚为什么第二种情况is允许。


Update:

这是一个未使用的完整示例readonly,并且还显示了一个非扩展方法,并演示了用法:

struct Foo
{
    internal int _x;

    // Can't compile, error CS8170
    // public ref int GetXRefMember() => ref _x;

    public int X => _x;
}

static class FooExtensions
{
    public static ref int GetXRefExtension( this ref Foo foo )
    {
        return ref foo._x;
    }

    public static ref int GetXRef( ref Foo foo )
    {
        return ref foo._x;
    }
}

class Program
{
    static void Main( string[] args )
    {
        var f = new Foo();
        Console.WriteLine( f.X );
        f.GetXRefExtension() = 123;
        Console.WriteLine( f.X );

        // You can also do it without using an extension method, but the caller is required to specify ref:
        FooExtensions.GetXRef( ref f ) = 999;
        Console.WriteLine( f.X );

        /* Output:
         * 0
         * 123
         * 999
         */
    }
}

有趣的是,扩展方法默默地“添加”ref,当正常调用需要调用者显式添加ref对于论点,我想把话说清楚,防止出错。


我认为这涵盖了参考只读提案 https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/readonly-ref.md,安全退货规则部分。

从结构成员返回“this”不安全

这个你已经知道了。您可以阅读更多有关为什么不允许的信息here https://github.com/dotnet/csharplang/blob/master/meetings/2015/LDM-2015-09-01.md#this-in-structs。简而言之 - 允许它“污染本地值类型上调用的任何引用返回方法”,因此allref 从结构上的方法返回不是“安全返回”,因为它们可能包含对此的引用。

ref/in 参数可以安全返回

只要接收者是,实例结构字段就可以安全返回 安全返回

这涵盖了静态方法的情况。foo参数可以安全返回(因为in),因此,foo._x可以安全返回,作为结构实例的字段,该实例本身可以安全返回。

如果所有引用/输出都可以安全地返回,则从另一个方法返回的引用 作为形式参数传递给该方法可以安全返回。

这可以防止上述静态方法出现问题。它使以下内容无效:

public static ref readonly int ExtensionGetX(in Foo foo) {
    return ref foo._x;
}

static ref readonly int Test() {
    var s = new Foo();
    s._x = 2;
    // fails to compile
    return ref ExtensionGetX(s);
}

Because s退货不安全,我们来自的参考ExtensionGetX返回也不安全,因此我们不能将指针泄漏到范围之外的局部变量。

简而言之 - 它是允许的,因为它是安全的,并且没有禁止从结构成员方法返回对“this”的引用的特定缺点。

更新。我不认为更新你的问题会改变我的答案。上述“安全返回”规则保持不变。你变了in to ref, but ref参数也可以安全返回。它的实例字段也是如此。但是如果你让参数返回不安全:

public static ref int GetXRef(Foo foo)
{
    return ref foo._x;
}

那么就编译不了了。

您还认为(在评论中)“您不能将返回的引用存储为局部变量”,但事实并非如此:

ref int y = ref FooExtensions.GetXRef(ref f);
y = 10;
// print 10
Console.WriteLine(f.X);

所以,无论是否只读,in or ref- 安全返回规则确保在这种情况下返回 ref struct 成员是安全的,同时允许返回引用thisfrom struct local 方法会产生不良后果,强制将所有结构成员返回的所有引用值视为不安全返回。

如果结构成员可以将 ref 返回到,则将不可能发生什么的小例子this:

public ref int GetXRefMember(ref int y) => ref y;

static ref int Test(ref int y) {
    var x = new Foo();
    // safe to return, but won't be if ref to `this` can
    // ever be returned from struct local method
    return ref x.GetXRefMember(ref y);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 C# 结构体方法不能返回对字段的引用,但非成员方法可以? 的相关文章

  • WinForms 应用程序中的初始化代码 - Program.cs 还是 MainForm?

    我有一个 Windows 窗体应用程序 当前在启动时加载数据库 流程是这样的 Program cs gt Application Run new MainForm gt MainForm 构造函数 gt 打开数据库 因此基本上 MainFo
  • C++ win32 控制台中的颜色

    std cout lt lt blblabla done lt lt std endl 是否有可能使 done 采用另一种颜色 并且可能是大胆的 我使用的是 Windows 7 这取决于您使用的操作系统 如果您使用的是您想要的 Window
  • 什么是 ADO.NET?

    我编写了一些 Access 数据库并使用了一些轻型 VBA 并且有一个 OO 类 现在我正在编写一个 C 数据库应用程序 我已经安装并连接了 VS 和 System Data SQLite 并输入了我的表和列 但这就是我陷入困境的地方 我正
  • 实体框架,高效的NavigationProperty.OfType查询

    我在使用每表类型 TPT 继承在 EF4 中构造有效查询时遇到问题 我有一个名为Episode 并且每个情节可以有多个事件 有几种不同类型的事件都源自称为Event 我想过滤不包含特定类型事件的所有剧集 Episode有一个导航属性 它是其
  • ASP.NET MVC:DropDownListFor 未选择任何选项

    我用它来填充 ASP NET MVC 视图中的下拉列表 调试这个我可以看到Selected属性设置为true当它应该是的时候 但是当渲染视图时 列表中的任何选项都不
  • Azure 搜索 .NET SDK 自定义分析器

    没有太多背景 这是我的问题 要使用 C 中的 NET SDK 创建新的 Azure 搜索索引 使用文档中提供的酒店示例 我的代码如下所示 public class Hotel System ComponentModel DataAnnota
  • 了解编译器如何在初始化中使用普通的 {}-list

    考虑以下玩具代码 class Y public Y int int cout lt lt Y ctor n class X public X initializer list
  • 计算串行通信的块校验字符 (BCC)

    我通过 NET 的 SerialPort 类通过串行与设备进行通信 并且根据第三方设备规范要求 我需要计算 块检查字符 我被告知的唯一信息是 这是一个异或运算 XOR 并且必须对所有角色执行 那么 如果我有字符串 Bob 001 将如何计算
  • 如何将 C# 6 与网站项目类型一起使用?

    更新了现有的Web Site项目类型Visual Studio 2015 我将Framework更改为4 6 然后我希望在我的代码隐藏文件中可以使用所有这些新功能 不幸的是我收到如下错误 错误 CS8026 功能 表达式主体属性 在 C 5
  • Mono.Cecil 类似 Type.GetInterfaceMap 之类的东西吗?

    系统 反射 类型包含获取接口映射 http msdn microsoft com en us library system type getinterfacemap aspx这有助于确定哪些方法从接口实现某些方法 Does 莫诺 塞西尔包含
  • CTAD 可以在模板类的成员内部使用吗?

    C 有一个有用的功能 即模板参数隐含在模板类内的代码中A 然而 对于建筑来说 这似乎与 CTAD 发生冲突 如何让 CTAD 优先 例如 这里有一个错误f会员因为A被解释为A
  • 是否有适用于 Amazon 产品 API 的最新 C# 示例?

    我正在尝试创建一个与亚马逊的产品 API 交互的小型应用程序 获取文章的价格等 不幸的是 到目前为止我发现的与 Amazon WCF 服务交互的所有 C 示例都已过时 我知道 Amazon 决定每个服务调用都必须使用个人 accessKey
  • OpenSubKey 不适用于我需要的注册表值

    我安装了 SQL Server In the registry the key MSSQLServer at HKEY LOCAL MACHINE SOFTWARE Microsoft looks like this 以下所有代码行都从注册
  • C# 中的时间跨度总和

    我有一个包含 TimeSpan 变量的对象集合 MyObject TimeSpan TheDuration get set 我想使用 LINQ 来计算这些时间的总和 当然 从 MyCollection 中的 r 选择 r TheDurati
  • boost::property_map 在 boost 中是如何实现的以及如何更改它

    我想知道属性映射是如何在提升图中实现的 例如 我的顶点和边属性定义如下 vertex property gt struct NodeInfo int a b c actual bundled property struct NodeInfo
  • 访问 ASP.NET 中 App_Code 中未声明的类

    我有时定义业务逻辑类来 帮助 我的 ASPX 代码隐藏类 对我来说 将它们都包含在代码隐藏文件中是最有意义的 因为它们一起工作 但是 我偶尔想从 App Code 中定义的更高级别的类访问业务逻辑类 但它们不能在文件外部自动访问 因此 问题
  • 在 C 中释放 NULL 指针是一个好习惯吗? [复制]

    这个问题在这里已经有答案了 可能的重复 ptr 为 NULL 的 free ptr 是否会损坏内存 https stackoverflow com questions 1938735 does freeptr where ptr is nu
  • 错误 C2601:“main”:本地函数定义非法 - MS VS 2013 编译器

    我正在用 C 编写一个小程序 当我尝试使用 MS VS 2013 编译器编译它时 出现错误 C2601 main 本地函数定义非法 这是什么意思 我的代码是 include
  • 在 C 中实现逻辑右移

    我正在致力于仅使用按位运算符在 C 中创建逻辑右移函数 这是我所拥有的 int logical right shift int x int n int size sizeof int size of int arithmetic shift
  • 如何在 C 中将向量参数传递给 OpenCL 内核?

    我在将向量类型 uint8 参数从 C 中的主机代码传递到 OpenCL 内核函数时遇到问题 在主机中 我将数据存储在数组中 cl uint dataArr 8 1 2 3 4 5 6 7 8 我的真实数据不仅仅是 1 8 这只是为了便于解

随机推荐

  • 获取 Android 操作系统中已注册的 Pending Intent 列表

    我注册了计划在给定时间执行的警报 并且根据计划列表的大小 可以有很多警报 但我有两个问题仍然不清楚 1 如何在操作系统中查询我注册的待处理意图 我需要这个来测试 我想要的伪代码是这样的 List
  • 如何向 ionic 4 应用程序添加和使用 bootstrap?

    我正在构建一个 ionic 4 应用程序 我想使用 bootstrap 而不使用 CDN 方法 我已经使用 npm install bootstrap 安装了 bootstrap 在 Ionic 4 中 可以通过使用 angular jso
  • 如何更改 PostgreSQL 中的最大列宽?

    我有一个简单的 SQL 查询 它从一个表中选择几行 其中一列包含很长的字符串 我想设置最大列宽 以便更容易阅读 我无法通过 pset 访问环境变量 None
  • 测试 SQL 查询的最佳方法[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我遇到了一个问题 复杂的 SQL 查询总是出错 从本质上讲 这会导致向错误的客户发送邮件以及其他类似的 问题 大家对于创建这样的 SQL 查询有
  • 如何在 Jetpack Compose Pager 中处理多个 TextField 焦点?

    我有一个寻呼机 每个页面上都有一个 TextField 我正在做过渡animateScrollToPage 如何让每个页面上的 TextField 获得焦点 当我给予Modifier focusRequster 到文本字段并检查index
  • 可选链的动态类型与赋值不同

    可选的链接返回always一个可选值 为了反映可以对 nil 值调用可选链接的事实 可选链接调用的结果始终是可选值 即使您正在查询的属性 方法或下标返回非可选值 Swift 编程语言 https developer apple com li
  • QComboBox 是否可以显示与其列表中不同的值?

    在 Linux 上使用 Qt 5 9 我有一个带有多个标签的 QComboBox qc new QComboBox qc gt addItem tr Red qc gt addItem tr Green qc gt addItem tr B
  • 用新的 Dataframe 替换一行

    我正在寻找一种更优雅的方法来从字典的值替换另一个数据帧中的数据帧 这是我必须使用的数据类型的示例 d 1 name bob age 22 Data 4 name sam age 30 Data 2 name tom age 20 Data
  • getDownloadUrl 是付费操作吗?

    我想知道是否getDownloadUrl在 Firebase 存储 Google Cloud Storage 上 一种获取存储上文件的公共 URL 的方法 是付费操作 即使读完之后文档 https cloud google com stor
  • DrawingPanel中刷新图片扩展了JPanel

    我必须在软件底部加载一个小图标 只是有一个加载 确定 错误图标 正如 http www article kth se lindsey JavaCourse Book Part1 Java Chapter06 images html 上的建议
  • 如何在服务器模式下运行H2数据库?

    我需要从我的应用程序以服务器模式启动 H2 数据库 尝试过以下代码 server Server createTcpServer start 这是连接的属性 javabase jdbc url jdbc h2 tcp localhost 90
  • Jekyll - 如何在根目录中创建页面?

    我正在使用 Jekyll 创建页面 文档建议 Jekyll 可以选择在根目录中创建页面 或为新页面创建新目录 From http jekyllrb com docs pages http jekyllrb com docs pages 页面
  • Log4Net 在单独的配置文件中

    我需要为新项目配置 log4net 当我将所有信息保存在 App config 文件中时 一切都工作得很好 我想把log4net的配置放在一个单独的配置文件中 取App1 config 这是我的 app config 完美运行
  • 三个不同表的内连接

    我在 Oracle APEX 工作 我想从三个不同的表中生成报告 患者 病史 治疗 通过INNER JOIN 表格如下 患者 Par Id Pk Pat Name Pat Gender 历史记录 His Id Pk Pat id Fk Tr
  • 生成精灵时指南针添加前斜线

    我刚刚生成了一个带有指南针的精灵 但由于某种原因 它在生成的类 url 中添加了一个前导斜杠 是否可以覆盖这个或者我的 config rb 中有什么错误 谢谢你的帮助 Joe 配置 rb gt http path css dir sass
  • 从嵌套列表创建新列表并将字符串转换为浮点数

    很抱歉问了一个已经被问过一百遍的问题 我是 Python 新手 我找到的解决方案似乎都不能解决我的问题 我有一个来自名为糖尿病的 csv 文件的嵌套列表 我在文件中读取并用逗号分隔元素 如下所示 for line in open diabe
  • .NET 日期时间转字符串

    有没有一种简单的方法可以将 DateTime 对象转换为这样的字符串表示形式 2010 03 03 10 38 48 我不确定上面的格式是什么 但它与通过 ToLongTimeString 等获得的模式不同 这是字符串生成器的情况吗 像这样
  • pyfunc_0 的返回值是 double,但需要 float

    我目前正在尝试更好地了解 Tensorflows CustomLayer 功能 在实现这样的自定义层时 我遇到了以下错误 usr lib python3 dist packages skimage util dtype py 110 Use
  • 在 CSS Grid 中为网格间隙设置不同的长度

    我正在使用 CSS 网格创建布局 并且希望每行之间有不同的空间 我可以通过在每个元素上使用边距来很好地创建布局 但这种方式掩盖了代码的简单性 有什么网格技巧可以实现这一点吗 grid row gap似乎只采用一个值 该值用于所有行 我想要实
  • 为什么 C# 结构体方法不能返回对字段的引用,但非成员方法可以?

    以下是结构体实例方法尝试将只读引用返回到结构体实例字段的示例 struct Foo internal int x public ref readonly int MemberGetX gt ref x Error CS8170 Struct