• 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/C++】用C语言写一个数据仓库,存储和修改数据
    数仓建设规范说明书
    Spring Boot Actuator 管理日志
    vue 子页面通过暴露属性,实现主页面的某事件的触发
    零束科技打通智驾全域数据闭环,加速智驾场景规模化量产落地!
    English Learning - L3 作业打卡 Lesson3 Day20 2023.5.24 周三
    单稳态中间继电器UEG/A-4DPDT/DC220V
    5分钟安装Kubernetes+带你轻松安装istio服务网格指南
    随笔
    【教程】Autojs使用OpenCV进行SIFT/BRISK等算法进行图像匹配
  • 原文地址:https://blog.csdn.net/qq_52855744/article/details/126795121