.NET中的结构和类有什么区别?


当前回答

基元值类型或结构类型的每个变量或字段都持有该类型的唯一实例,包括其所有字段(公共和私有)。相比之下,引用类型的变量或字段可能为空,或者可能引用存储在其他位置的对象,其他引用也可能存在。结构的字段将存储在与该结构类型的变量或字段相同的位置,该变量或字段可能位于堆栈上,也可能是另一个堆对象的一部分。

创建原始值类型的变量或字段将使用默认值创建它;创建结构类型的变量或字段将创建一个新实例,以默认方式创建其中的所有字段。创建引用类型的新实例将首先以默认方式创建其中的所有字段,然后根据类型运行可选的附加代码。

将一个基本类型的变量或字段复制到另一个将复制值。将结构类型的一个变量或字段复制到另一个变量将前一个实例的所有字段(公共和私有)复制到后一个实例。将一个引用类型的变量或字段复制到另一个将导致后者引用与前者相同的实例(如果有的话)。

需要注意的是,在某些语言(如C++)中,类型的语义行为与它的存储方式无关,但在.NET中则不是这样。如果一个类型实现了可变值语义,则将该类型的一个变量复制到另一个变量会将第一个实例的财产复制到第二个实例所引用的另一个实例,并且使用第二个实例的成员来变异它将导致第二个例子被改变,而不是第一个。如果一个类型实现了可变的引用语义,那么将一个变量复制到另一个变量并使用第二个变量的成员来变异对象将影响第一个变量所引用的对象;具有不可变语义的类型不允许变异,因此复制是创建新实例还是创建对第一个实例的另一个引用在语义上无关紧要。

在.NET中,值类型可以实现上述任何语义,前提是它们的所有字段都可以这样做。然而,引用类型只能实现可变引用语义或不可变语义;具有可变引用类型字段的值类型限于实现可变引用语义或奇怪的混合语义。

其他回答

结构是实际值-它们可以为空,但不能为空

这是正确的,但是也要注意,从.NET2开始,结构支持Nullable版本,C#提供了一些语法糖,使其更易于使用。

int? value = null;
value  = 1;

结构与等级

结构是一种值类型,因此它存储在堆栈上,但类是一种引用类型,存储在堆上。

结构不支持继承和多态,但类同时支持两者。

默认情况下,所有结构成员都是公共的,但类成员在本质上默认是私有的。

由于结构是一种值类型,我们不能将null赋给结构对象,但类的情况并非如此。

我♥ 可视化,在这里我创建了一个来展示结构和类之间的基本区别。


以及文本表示,以防万一;)

+--------------------------------------------------+------+----------------------------------------------+
|                      Struct                      |      |                      Class                    |
+--------------------------------------------------+------+----------------------------------------------+
| - 1 per Thread.                                  |      | - 1 per application.                         |
|                                                  |      |                                              |
| - Holds value types.                             |      | - Holds reference types.                     |
|                                                  |      |                                              |
| - Types in the stack are positioned              |      | - No type ordering (data is fragmented).     |
|   using the LIFO principle.                      |      |                                              |
|                                                  |      |                                              |
| - Can't have a default constructor and/or        |      | - Can have a default constructor             |
|   finalizer(destructor).                         |      |   and/or finalizer.                          |
|                                                  |      |                                              |
| - Can be created with or without a new operator. |      | - Can be created only with a new operator.   |
|                                                  |      |                                              |
| - Can't derive from the class or struct          |  VS  | - Can have only one base class and/or        |
|   but can derive from the multiple interfaces.   |      |   derive from multiple interfaces.           |
|                                                  |      |                                              |
| - The data members can't be protected.           |      | - Data members can be protected.             |
|                                                  |      |                                              |
| - Function members can't be                      |      | - Function members can be                    |
|   virtual or abstract.                           |      |   virtual or abstract.                       |
|                                                  |      |                                              |
| - Can't have a null value.                       |      | - Can have a null value.                     |
|                                                  |      |                                              |
| - During an assignment, the contents are         |      | - Assignment is happening                    |
|   copied from one variable to another.           |      |   by reference.                              |
+--------------------------------------------------+------+----------------------------------------------+

有关更多信息,请查看以下内容:

类和结构(官方文档)。在类和结构之间选择(官方文档)。

如前所述:类是引用类型,而结构是具有所有后果的值类型。

根据经验,框架设计指南建议在以下情况下使用结构而不是类:

它的实例大小小于16字节它逻辑上表示单个值,类似于原始类型(int、double等)它是不可变的它不必经常装箱

除了访问说明符的基本区别,以及上面提到的几个区别之外,我还想添加一些主要区别,包括上面提到的一些区别,以及带有输出的代码示例,这将提供对引用和值的更清晰的了解

结构:

是值类型,不需要堆分配。内存分配不同,存储在堆栈中适用于小型数据结构影响性能,当我们将值传递给方法时,我们会传递整个数据结构,所有数据都传递给堆栈。构造函数只返回结构值本身(通常在堆栈上的临时位置),然后根据需要复制该值每个变量都有自己的数据副本,其中一个变量的操作不可能影响另一个变量。不支持用户指定的继承,它们隐式继承自类型对象

类别:

参考类型值存储在堆中存储对动态分配对象的引用构造函数是用new运算符调用的,但它不会在堆上分配内存多个变量可以引用同一对象对一个变量的操作可能会影响另一个变量引用的对象

代码示例

    static void Main(string[] args)
    {
        //Struct
        myStruct objStruct = new myStruct();
        objStruct.x = 10;
        Console.WriteLine("Initial value of Struct Object is: " + objStruct.x);
        Console.WriteLine();
        methodStruct(objStruct);
        Console.WriteLine();
        Console.WriteLine("After Method call value of Struct Object is: " + objStruct.x);
        Console.WriteLine();

        //Class
        myClass objClass = new myClass(10);
        Console.WriteLine("Initial value of Class Object is: " + objClass.x);
        Console.WriteLine();
        methodClass(objClass);
        Console.WriteLine();
        Console.WriteLine("After Method call value of Class Object is: " + objClass.x);
        Console.Read();
    }
    static void methodStruct(myStruct newStruct)
    {
        newStruct.x = 20;
        Console.WriteLine("Inside Struct Method");
        Console.WriteLine("Inside Method value of Struct Object is: " + newStruct.x);
    }
    static void methodClass(myClass newClass)
    {
        newClass.x = 20;
        Console.WriteLine("Inside Class Method");
        Console.WriteLine("Inside Method value of Class Object is: " + newClass.x);
    }
    public struct myStruct
    {
        public int x;
        public myStruct(int xCons)
        {
            this.x = xCons;
        }
    }
    public class myClass
    {
        public int x;
        public myClass(int xCons)
        {
            this.x = xCons;
        }
    }

输出

Struct Object的初始值为:10

内部结构方法Struct对象的内部方法值为:20

结构对象的方法调用值为:10

类对象的初始值为:10

内部类方法类对象的内部方法值为:20

类对象的方法调用值为:20

在这里,您可以清楚地看到按值调用和按引用调用之间的区别。