• C# 值类型调用ToString一定会装箱吗?


    答案

    可能会装箱。

    解释

    为什么是可能会装箱呢?
    首先我们复习下装箱拆箱的概念

    • 装箱:值类型转换成引用类型
    • 拆箱:引用类型转换为值类型

    那么如果要装箱,原来的类型一定要是值类型,目标类型一定要是引用类型

    什么是值类型?ValueType是什么?

    值类型其实就是ValueType
    我们先来看ValueType里面有什么

    namespace System
    {
        public abstract class ValueType
        {
            protected ValueType();
    
            public override bool Equals(object obj);
            public override int GetHashCode();
            public override string ToString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    首先,可以确定的是,ValueType是一个class,也就是一个类,但是它重写了Equals方法,那么ValueType对象在和其他对象做比较的时候,会和class有不同的处理方式,这也就是值类型引用类型不同的根源。

    然后这里有个非常重要的地方,我们发现ValueType重写了ToString方法,我们先记住这里,再看看后面。

    int是什么类型?

    拿C#的int来做例子吧。
    首先C#的int,它是System.Int32的简称,而System.Int32它是结构体,结构体都是默认继承ValueType,所以结构体是值类型。也就是说int就是值类型。

    namespace System
    {
        public struct Int32 : IComparable, IComparable<Int32>, IConvertible, IEquatable<Int32>, IFormattable
        {
            public const Int32 MaxValue = 2147483647;
            public const Int32 MinValue = -2147483648;
    
            public static Int32 Parse(string s, IFormatProvider provider);
            public static Int32 Parse(string s, NumberStyles style, IFormatProvider provider);
            public static Int32 Parse(string s, NumberStyles style);
            public static Int32 Parse(string s);
            public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out Int32 result);
            public static bool TryParse(string s, out Int32 result);
            public Int32 CompareTo(object value);
            public Int32 CompareTo(Int32 value);
            public bool Equals(Int32 obj);
            public override bool Equals(object obj);
            public override Int32 GetHashCode();
            public TypeCode GetTypeCode();
            public override string ToString();
            public string ToString(IFormatProvider provider);
            public string ToString(string format);
            public string ToString(string format, IFormatProvider provider);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    我们发现,int也是重写了ToString方法,也就是说,它会调用自己实现的ToString方法,而不是调用父类的ToString方法。

    判断是否装箱的诀窍

    看值类型有没有进行装箱,就看他有没有装换成Object或者值类型所继承的接口类型

    实例

    那么我们来看下方的代码

    int age = 5;
    string str = age.ToString();
    
    • 1
    • 2

    我们先复习下

    1. 装箱:值类型转换成引用类型
    2. int是值类型
    3. int重写了ToString方法

    请问:上面的代码装箱了吗?

    先不揭晓答案。我们来看看ToString过程。

    1. age调用ToString方法,去int类型中寻找有没有ToString方法。
    2. 发现int重写了ToString方法,直接调用intToString方法。

    答案:没有发生装箱。
    原因:int自身有ToString的实现,所以就没有向父类查找了。也就不会发生装箱操作了。

    拓展

    我们可以自定义一个结构体,让他重新ToString方法,也不会发生装箱操作。

    public struct A
    {
        public int age;
        public string name;
        public A(int age, string name)
        {
            this.age = age;
            this.name = name;
        }
        public override string ToString()
        {
            return name;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    如果我们不重写会怎么样呢?

    public struct B
    {
        public int age;
        public string name;
        public B(int age, string name)
        {
            this.age = age;
            this.name = name;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    答案是会装箱,因为ValueType本身是类,所以如果自身没有实现ToString方法,会从父类去寻找,然后找到了ValueType,但是ValueType是一个类,所以这个时候发生了多态,也就是从值类型转换成引用类型了,所以此时发生了装箱。

    最后需要注意

    我们在写代码的时候,字符串拼接比较常用,比如string和int拼接。

    测试环境

    Unity

    第一种写法

    private void Update()
    {
        string s = "";
        int num = 1;
        s += num.ToString();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    第二种写法

    private void Update()
    {
        string s = "";
        int num = 1;
        s += num;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    所以我们需要多注意这个问题。

  • 相关阅读:
    C++算法之旅、04 基础篇 | 第一章 基础算法
    ansible-第二天
    世界首部使用USB-C接口iPhone面世
    第2关:子节点创建、列出、删除
    Mysql中MyISAM和InnoDB 引擎的区别
    Notion Like 笔记软件使用教程·学习资源汇总·知识管理方案
    c语言练习72:关于截断和整形提升
    时序预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元时间序列预测
    凭着这份《微服务架构实战》,带你立足实战落地微服务架构
    【Git-2022总结】分布式代码版本控制工具【GitHub/Gitee/GitLab】
  • 原文地址:https://blog.csdn.net/qq_52855744/article/details/126795121