C# 中的拳击发生

2024-04-15

我正在尝试收集 C# 中发生装箱的所有情况:

  • 将值类型转换为System.Object type:

    struct S { }
    object box = new S();
    
  • 将值类型转换为System.ValueType type:

    struct S { }
    System.ValueType box = new S();
    
  • 将枚举类型的值转换为System.Enum type:

    enum E { A }
    System.Enum box = E.A;
    
  • 将值类型转换为接口引用:

    interface I { }
    struct S : I { }
    I box = new S();
    
  • 在 C# 字符串连接中使用值类型:

    char c = F();
    string s1 = "char value will box" + c;
    

    note:的常数char类型在编译时连接

    note:自 6.0 版本起 C# 编译器优化串联 https://github.com/dotnet/roslyn/pull/415涉及bool, char, IntPtr, UIntPtr types

  • 从值类型实例方法创建委托:

    struct S { public void M() {} }
    Action box = new S().M;
    
  • 在值类型上调用非重写的虚拟方法:

    enum E { A }
    E.A.GetHashCode();
    
  • 使用 C# 7.0 下的常量模式is表达:

    int x = …;
    if (x is 42) { … } // boxes both 'x' and '42'!
    
  • C# 元组类型转换中的装箱:

    (int, byte) _tuple;
    
    public (object, object) M() {
      return _tuple; // 2x boxing
    }
    
  • 可选参数object具有值类型默认值的类型:

    void M([Optional, DefaultParameterValue(42)] object o);
    M(); // boxing at call-site
    
  • 检查无约束泛型类型的值null:

    bool M<T>(T t) => t != null;
    string M<T>(T t) => t?.ToString(); // ?. checks for null
    M(42);
    

    note:这可能会在某些 .NET 运行时中通过 JIT 进行优化

  • 无约束或的型式试验值struct泛型类型与is/as运营商:

    bool M<T>(T t) => t is int;
    int? M<T>(T t) => t as int?;
    IEquatable<T> M<T>(T t) => t as IEquatable<T>;
    M(42);
    

    note:这可能会在某些 .NET 运行时中通过 JIT 进行优化

您还知道其他可能是隐藏的拳击情况吗?


这是一个很好的问题!

发生装箱的原因只有一个:当我们需要对值类型的引用时。您列出的所有内容都属于此规则。

例如,由于对象是引用类型,因此将值类型转换为对象需要对值类型的引用,这会导致装箱。

如果您希望列出每种可能的情况,还应该包括派生类,例如从返回对象或接口类型的方法返回值类型,因为这会自动将值类型转换为对象/接口。

顺便说一句,您敏锐地识别出的字符串连接情况也是源自于对象的转换。 + 运算符由编译器转换为对 string 的 Concat 方法的调用,该方法接受您传递的值类型的对象,因此会强制转换为对象,从而发生装箱。

多年来,我一直建议开发人员记住装箱的单一原因(我在上面指定),而不是记住每一个案例,因为列表很长而且很难记住。这也有助于理解编译器为 C# 代码生成的 IL 代码(例如,字符串上的 + 会产生对 String.Concat 的调用)。当您对编译器生成的内容有疑问并且发生装箱时,您可以使用 IL 反汇编器 (ILDASM.exe)。通常,您应该查找装箱操作码(只有一种情况可能会发生装箱,即使 IL 不包含装箱操作码,下面有更多详细信息)。

但我确实同意有些拳击事件不太明显。您列出了其中之一:调用值类型的非重写方法。事实上,由于另一个原因,这一点不太明显:当您检查 IL 代码时,您看不到装箱操作码,而是看到约束操作码,因此即使在 IL 中,装箱发生也不明显!我不会详细说明为什么要防止这个答案变得更长......

不太明显装箱的另一种情况是从结构调用基类方法时。例子:

struct MyValType
{
    public override string ToString()
    {
        return base.ToString();
    }
}

这里 ToString 被重写,因此在 MyValType 上调用 ToString 不会生成装箱。但是,该实现调用基本 ToString 并导致装箱(检查 IL!)。

顺便说一句,这两个不明显的拳击场景也源自上述单一规则。当在值类型的基类上调用方法时,必须有一些东西可以用于this关键字来参考。由于值类型的基类(始终)是引用类型,因此this关键字必须引用引用类型,因此我们需要对值类型的引用,因此由于单一规则而发生装箱。

以下是我的在线 .NET 课程中详细讨论拳击部分的直接链接:http://motti.me/mq http://motti.me/mq

如果您只对更高级的拳击场景感兴趣,这里有一个直接链接(尽管上面的链接一旦讨论了更基本的内容也将带您到那里):http://motti.me/mu http://motti.me/mu

我希望这有帮助!

Motti

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

C# 中的拳击发生 的相关文章

随机推荐

  • Scala - 以函数方式修改字符串

    我刚刚开始使用 Scala 因此开始以更实用的方式做事 只是想知道是否有一种更实用的方法来实现如下所示的功能 def expand exp String String var result exp for k v lt libMap res
  • Python/Django 中的音频波形可视化

    我已经在 Stack Overflow 上寻找这个问题的答案 但似乎没有地方给出正确的答案或方向 我的项目将允许用户上传 WAV 最终将在服务器上使用 FFmpeg 将其转换为低质量 MP3 并将全部存储在 Amazon S3 上并提供服务
  • asp.net mvc - ActionLink 的渲染不一致

    我有一个控制器 它接受以下两种格式的 URL 网络 添加或编辑 gt 在页面上呈现空白表单以添加新的网络对象 网络 AddOrEdit id gt 使用预填充表单呈现页面以编辑网络对象 带有 ID id 显然 每个实例中都使用相同的视图 我
  • 在 JavaScript 中逐行动态添加字幕到视频元素

    我想知道目前是否可行 下面是我的 HTML
  • Chrome DevTools 中缺少“添加到主屏幕”链接

    使用 Google 服务可能会令人沮丧 他们有令人难以置信的文档 但文档总是假设一切正常 如果有什么东西不像广告上说的那样有效 那你就完全靠自己了 没有错误消息 没有解决问题的帮助 甚至没有承认某些事情可能不起作用 以防万一 添加到主屏幕
  • 如何检索 C99 可变参数宏的最后一个参数?

    Visual Studio 失败的 static assert 错误消息完全由错误代码和 static assert 的第二个参数组成 没有任何其他消息表明这是静态断言失败 我想做一个宏来解决这个问题 例如 作为第一次尝试 define S
  • Winforms MVP

    我主要有 ASP Net 背景 懂一些 MVC 我也做了一些 Silverlight 和 MVVM 但是我现在即将转向 Winforms 我对它的经验很少 所以我想知道如何处理 MVP 典型的 MVP 示例显示演示者设置视图属性 通过某种
  • 如何从表中选择除最后 100 条之外的所有记录

    我有一个存储客户记录的数据库 我想设置一个 cron 作业来定期覆盖这些记录 我想说 Select from ORDERS where ORDER ID 不在列表的前 100 名中 每行都有自己的 order id 最新的 order id
  • 多个App服务使用同一个域名

    我们有一个场景 我们有多个 azure 应用程序服务 并且部署了 Web API 但是我们需要所有应用程序服务使用相同的域名 而不是子域 例如http example com api1 http example com api1在一个应用程
  • Postgres:在一项选择中获取最小值、最大值、聚合值

    我正在使用 Postgresql 8 4 我有一个这样的表 type value 1 5 2 6 1 4 3 10 我想写一个选择 它将给我最小值和最大值 以及所有类型的聚合integer 期望的结果应该是 min max types 4
  • SQL 连接具有特定条件的两个表

    表A结构 表B结构 上面是两个表 TableB TableARelationID是一个relationID 用于映射表A 期望的输出 期望的结果将采用 TableA RecordID 和 TableB Text 但仅采用表 B 中的类型 2
  • 在Python中不使用全局变量跟踪递归调用的数量

    如何在 Python 中不使用全局变量来跟踪递归调用的次数 例如 如何修改以下函数来跟踪调用次数 def f n if n 1 return 1 else return n f n 1 print f 5 这是一个不使用全局的巧妙技巧 您可
  • 使用 PHP Curl 发布数据并检索响应?

    我对使用网络服务非常陌生 所以我发现这很令人困惑 如果我有一个 URL 我想向其发布一些 JSON 数据 我知道如何使用 CURL PHP 方法来执行此操作 我想知道的是 如果我这样做 并且 URL 有某种服务器响应 我如何在我的 php
  • 如何选择30天的数据?

    我有疑问 SELECT name FROM SELECT name FROM Hist answer WHERE id city 34324 AND datetime gt DATE SUB CURRENT DATE INTERVAL 1
  • 如何列出导入的模块?

    如何枚举所有导入的模块 例如 我想得到 os sys 从这段代码 import os import sys import sys sys modules keys 仅获取当前模块的所有导入的近似方法是检查globals https docs
  • 来自 MDTool 的 .IPA 文件

    如何让 MDTool 为我的 MonoTouch 项目创建 IPA 文件 当我从 MonoDevelop GUI 应用程序中构建时 会创建 IPA 文件 But mdtool build configuration AppStore iPh
  • 静态文件application_可读用法

    我一直在尝试了解 application read 静态 url 处理程序字段的工作原理 我使用的是 SDK 版本 1 7 7 并且我已在开发环境中的应用程序上将其设置为 true 但我似乎无法实际读取该文件 app yaml url te
  • Scala 相当于 F# 中的 |> 或 Clojure 中的 ->>

    在 Scala 中 当我有这个表达式时 f1 f2 f3 p 有没有一种方法可以让我使用类似的东西 F p gt f3 gt f2 gt f1 还是 Clojure gt gt p f3 f2 f1 Scala 中没有相当于 F 的管道运算
  • 如何在一个 Tomcat + Apache 上部署多个 Grails 应用程序?

    我已经阅读了 StackOverflow 上的几个问题 并用 google 搜索了几个小时 但对于在一个 tomcat 5 5 使用 Apache 上部署多个 Grails 应用程序的问题 我找不到完整且清晰的答案 也许有人可以把我推向正确
  • C# 中的拳击发生

    我正在尝试收集 C 中发生装箱的所有情况 将值类型转换为System Object type struct S object box new S 将值类型转换为System ValueType type struct S System Va