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


当前回答

首先,结构是通过值而不是引用传递的。结构适用于相对简单的数据结构,而类通过多态性和继承从体系结构的角度来看具有更大的灵活性。

其他人可能会比我给你更多的细节,但当我所追求的结构很简单时,我会使用结构。

其他回答

类的实例存储在托管堆上。“包含”实例的所有变量都只是对堆上实例的引用。将对象传递给方法会导致传递引用的副本,而不是对象本身。

结构(从技术上讲,值类型)存储在使用它们的任何地方,很像原始类型。运行时可以随时复制内容,而无需调用自定义的复制构造函数。将值类型传递给方法涉及复制整个值,同样无需调用任何自定义代码。

C++/CLI名称使这种区别更加明显:“ref class”是第一个类,“value class”是第二个类。C#使用的关键字“class”和“struct”只是必须学习的东西。

结构和类别之间的差异:

结构是值类型,而类是引用类型。结构存储在堆栈上,而类存储在堆值类型将其值保存在声明它们的内存中,但引用类型保存对内存中对象的引用。值类型在作用域丢失后立即销毁,而引用类型仅在作用域丢失后销毁变量。该对象随后被垃圾收集器销毁。将结构复制到另一个结构时,该结构的新副本创建。修改的结构不会影响其他结构。将一个类复制到另一个类时,它只复制参考变量。两个引用变量都指向堆上的同一对象。对一个变量所做的更改将影响另一个参考变量。结构不能有析构函数,但类可以有析构器。结构不能具有显式无参数构造函数,而类可以。结构不支持继承,但类支持支持从接口继承。结构为密封型。

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

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

int? value = null;
value  = 1;

除了其他答案之外,还有一个基本的区别值得注意,那就是数据如何存储在数组中,因为这会对性能产生重大影响。

对于结构,数组包含结构的实例对于类,数组包含指向内存中其他位置的类实例的指针

因此,内存中的结构数组如下所示

[结构][结构]〔结构〕〔结构〕

而类数组看起来像这样

指针

对于一个类数组,您感兴趣的值不会存储在数组中,而是存储在内存的其他位置。

对于绝大多数应用程序来说,这种差异并不重要,但是,在高性能代码中,这将影响内存中数据的位置,并对CPU缓存的性能产生很大影响。在可以/应该使用结构的情况下使用类将大大增加CPU上的缓存未命中数。

现代CPU做的最慢的事情不是处理数字,而是从内存中提取数据,一级缓存命中速度比从RAM读取数据快很多倍。

下面是一些可以测试的代码。在我的机器上,遍历类数组所需的时间大约是结构数组的3倍。

    private struct PerformanceStruct
    {
        public int i1;
        public int i2;
    }

    private class PerformanceClass
    {
        public int i1;
        public int i2;
    }

    private static void DoTest()
    {
        var structArray = new PerformanceStruct[100000000];
        var classArray = new PerformanceClass[structArray.Length];

        for (var i = 0; i < structArray.Length; i++)
        {
            structArray[i] = new PerformanceStruct();
            classArray[i] = new PerformanceClass();
        }

        long total = 0;
        var sw = new Stopwatch();
        sw.Start();
        for (var loops = 0; loops < 100; loops++)
        for (var i = 0; i < structArray.Length; i++)
        {
            total += structArray[i].i1 + structArray[i].i2;
        }

        sw.Stop();
        Console.WriteLine($"Struct Time: {sw.ElapsedMilliseconds}");
        sw = new Stopwatch();
        sw.Start();
        for (var loops = 0; loops < 100; loops++)
        for (var i = 0; i < classArray.Length; i++)
        {
            total += classArray[i].i1 + classArray[i].i2;
        }

        Console.WriteLine($"Class Time: {sw.ElapsedMilliseconds}");
    }

在.NET中,有两类类型,引用类型和值类型。

结构是值类型,类是引用类型。

一般的区别是,引用类型存在于堆中,值类型存在于内联中,也就是说,在定义变量或字段的任何位置。

包含值类型的变量包含整个值类型值。对于结构,这意味着变量包含整个结构及其所有字段。

包含引用类型的变量包含指针,或对内存中实际值所在位置的引用。

首先,这有一个好处:

值类型始终包含值引用类型可以包含空引用,这意味着它们此刻根本不引用任何内容

在内部,引用类型被实现为指针,并且知道变量赋值是如何工作的,还有其他行为模式:

将值类型变量的内容复制到另一个变量中,将整个内容复制到新变量中,使这两个变量不同。换句话说,复制后,对其中一个的更改不会影响另一个将一个引用类型变量的内容复制到另一个变量中,就会复制引用,这意味着现在有两个引用指向实际数据的同一个存储位置。换句话说,在复制之后,更改一个引用中的数据似乎也会影响另一个引用,但这只是因为您实际上只是在两个地方查看相同的数据

当您声明变量或字段时,以下是两种类型的区别:

变量:值类型位于堆栈上,引用类型位于堆栈中,作为指向堆内存中实际内存所在位置的指针(请注意EricLipperts系列文章:堆栈是一个实现细节)类/结构字段:值类型完全位于类型内部,引用类型位于类型内部作为指向堆内存中实际内存所在位置的指针。