最近笔者面试一些人,发现很多工作10年的人一些基础问题都答不好
记得当年自己大学刚学编程时,侯捷老师的《深入浅出MFC》开篇第一句“勿在浮沙筑高台”。项目如同建筑,下一层必须比上一层坚固,否则会垮塌。
如果我问你class类型和struct类型是引用类型还是值类型,你会要思考一下么,当然如果你是大佬请绕道
我们来复习一下c#中引用类型和值类型的一些基础概念:
在 C# 中,值类型和引用类型是两种不同的类型。它们有以下几个主要区别:
存储方式:值类型的实例直接存储在栈上,而引用类型的实例存储在堆上,栈上只存储引用(指向堆中实例的指针)。
传递方式:值类型的实例在传递时是通过值拷贝传递的,而引用类型的实例在传递时是通过引用拷贝传递的。
生命周期:值类型的实例的生命周期与其所在的作用域相同,而引用类型的实例的生命周期可能会超过其所在的作用域,因为引用可能会被传递到其他作用域中。
默认值:值类型的默认值是其零值(例如,整数类型的默认值为0),而引用类型的默认值是 null。
比较方式:值类型的比较是按值比较的,而引用类型的比较是按引用比较的(即比较两个引用是否指向同一个对象)。
需要注意的是,C# 中的一些类型(如字符串)虽然是引用类型,但是它们的行为更像值类型,因为它们的实例在不可变时可以被重用,而不需要在堆上创建新的实例。此外,结构体(struct)也是值类型,但是可以像类一样拥有方法和属性。
Type[] types = new Type[] {
typeof(int),
typeof(string),
typeof(object),
typeof(decimal),
typeof(double),
typeof(float),
typeof(structs),
typeof(Program)
};
foreach (Type type in types)
{
Console.WriteLine($"{type.Name} is{(type.IsValueType ? " not" : "")} a reference type");
}
![](https://i-blog.csdnimg.cn/blog_migrate/c640bc9a6abf659c2fcb3bb514780a56.png)
好的,看完上面,你应该有所新的收获,现在在问你一个问题,一个类里面的一个int型数据是值类型还是引用类型呢?
我们根据这个在复习下装箱和拆箱的概念
在 Unity 中,装箱和拆箱与在标准的 C# 中是相同的。装箱是指将值类型(例如结构体)转换为引用类型(例如对象),而拆箱是指将引用类型转换回值类型。
下面是一些关于装箱和拆箱在 Unity 中的简单说明:
装箱:装箱是将值类型转换为对象类型的过程。当你将一个值类型(例如 int、float 或自定义结构体)赋值给一个对象类型(例如 object 或 System.Collections.ArrayList)时,就会发生装箱。装箱操作会在堆上创建一个新的对象,并将值类型的实例复制到新的对象中。这可能会导致性能问题,因为它需要进行额外的内存分配和复制操作。
拆箱:拆箱是将对象类型转换回值类型的过程。当你从一个对象类型(例如 object 或 System.Collections.ArrayList)中提取一个值类型时,就会发生拆箱。拆箱操作将从对象中提取值类型实例,并将其复制到一个新的值类型变量中。这也可能会导致性能问题,因为它需要进行额外的内存分配和复制操作。
因此,在 Unity 中,尽量避免进行频繁的装箱和拆箱操作,特别是在性能敏感的代码路径中,因为它们可能会对游戏性能产生负面影响。如果可能的话,可以使用泛型类型(例如 List<T>、Dictionary<TKey, TValue> 等)来避免装箱和拆箱操作,因为它们可以处理任意类型的值类型,而不需要进行装箱和拆箱操作。
拆箱为啥消耗性能:
拆箱(Unboxing)是将值类型从对象类型转换回原始值类型的过程。在 C# 中,值类型被封装为对象类型(装箱)后,如果需要使用原始值类型,就需要进行拆箱操作。拆箱是一种显式的类型转换,因为值类型和对象类型之间是不兼容的。
拆箱操作消耗性能的原因主要有以下几点:
类型转换:拆箱是一种从 object 类型到具体值类型的转换过程,需要进行类型检查和转换操作。这涉及到额外的运行时检查和计算,导致了性能损失。
内存复制:拆箱操作通常涉及将堆上的值类型复制到栈上或堆上的另一个位置,以便在使用时能够直接访问值类型的数据。这涉及到额外的内存复制,增加了处理时间和内存开销。
垃圾回收(GC)压力:拆箱可能导致频繁的装箱和拆箱操作,这意味着在堆上创建和销毁对象,增加了垃圾回收的负担。频繁的垃圾回收可能导致应用程序性能下降。
值类型不适合装箱:值类型本身设计为在栈上分配内存,以便快速访问和高性能。但装箱操作将其转换为引用类型,使得它们在堆上分配内存,而且无法直接访问,从而降低了性能。
为了避免拆箱操作,应该尽量避免在值类型和 object 类型之间频繁进行转换。如果确实需要在值类型和引用类型之间进行转换,可以使用泛型和装箱技术来优化性能。使用泛型可以避免装箱,从而提高性能。同时,了解在什么情况下会发生装箱和拆箱操作也是优化性能的重要一环。
问题来了,当你从一个struct类型去访问object父节点类型里面的一个方法Equals方法,是拆箱还是装箱呢?
答案我会在我的公众号公布,回复"拆箱"获得