一般情况大家都使用类,但是Struct也是比较实用的一个类型,可能新手不知道他们有什么区别,我在这里总结了一下,方便新手学习,下面是我用.net Core 6写了一个demo
- 值类型虽然继承自ValueType,但是值类型的方法调用时会进行值类型拆装箱操作,因此性能上可能会有一些损耗。
- 值类型可以实现接口,通过实现接口可以为值类型添加一些行为和功能。例如,可以定义一个值类型的结构体,实现IComparable接口,来实现结构体之间的比较。
- 值类型是可以定义构造函数重载的,通过构造函数重载可以为值类型提供不同的构造方式。
- 值类型的内存分配和释放是由系统自动管理的,当值类型超出其作用域时,内存会立即被释放。
而引用类型的内存管理是通过垃圾回收器进行的,当垃圾回收器判断某个对象不再被引用时,才会将其内存释放。
这个是一个房间类
public class Room
{
public int RoomID { get; set; }
public string RoomName { get; set; }
}
这个是人类
public class Person
{
public int PersonID { get; set; }
public string PersonName { get; set; }
public Room Room { get; set; }
public void GetRoom(Room room) {
room.RoomName = PersonName + "_" + room.RoomName;
Room = room;
}
}
这里person类做了一件事情就是,他拿到房间之后,通过GetRoom方法修改了房间名称,当然这样他只是为了给自己的房间起一个别名,但是这个做法已经影响原本房间的名称
//初始化房间
var room = new Room() { RoomName = "房间A", RoomID=1 };
Console.WriteLine("原始的room Name: "+room.RoomName);
var person = new Person() { PersonName = "张三", PersonID=110 };
//张三住进去给自己房间起来一个别名
person.GetRoom(room);
Console.WriteLine("Person room: "+person.Room.RoomName);
//影响了原本的房间名称,不能因为张三住了之后,房间名字就变成这个样子了
Console.WriteLine("修改后的 room: "+room.RoomName);
下面是运行输出结果:
想象,如果有李四,是不是他住了之后又会影响房间的名称呢,答案是:肯定会影响的
如果不想影响原本房间的名称需要怎么处理呢,很简单
把类改成结构问题就解决了
public struct Room
{
public int RoomID { get; set; }
public string RoomName { get; set; }
}
再次运行代码:
房间A,还是房间A,就算是李四住了之后(new person=‘李四’),还是房间A
--但是如果某天来了一个伟人,如果他住过之后,房间名称就得换名字,这个时候怎么办呢?可以通过ref方式改变
完整的代码如下:
public struct Room
{
public int RoomID { get; set; }
public string RoomName { get; set; }
}
public class Person
{
public int PersonID { get; set; }
public string PersonName { get; set; }
//currentRoom 这个也是不能修改,如果currentRoom 和Room 修改就会数据导致不一致
private Room currentRoom = new();
//因为是伟人,所以这里特殊处理, ref readonly 这里变量就不允许修改了
public ref readonly Room Room { get { return ref currentRoom; } }
public void GetRoom(ref Room room) {
room.RoomName = PersonName + "_" + room.RoomName;
currentRoom = room;
}
}
//初始化房间
var room = new Room() { RoomName = "房间A", RoomID=1 };
Console.WriteLine("原始的room Name: "+room.RoomName);
var person = new Person() { PersonName = "黎明", PersonID=110 };
//黎明住进来之后,房间就有名气了,所以换名字了
person.GetRoom(ref room);
Console.WriteLine("Person room: "+person.Room.RoomName);
//黎明来了之后,之后房间就用黎明定义
Console.WriteLine("修改后的 room: "+room.RoomName);
运行之后输出结果如下,可以通过ref方式把值引用变成class引用
important: Changing a type from a class
to a struct
can change the semantics of your program. When a class
type is passed to a method, any mutations made in the method are made to the argument. When a struct
type is passed to a method, and mutations made in the method are made to a copy of the argument. That means any method that modifies its arguments by design should be updated to use the ref
modifier on any argument type you've changed from a class
to a struct
.
官网说的上面这段话,意思就是传递类,方法内改变参数值,会对原参数参数影响,而结构不会,
当传递结构的时候,传递的是结构的副本,所以不会对原参数产生影响