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


当前回答

在.NET中,结构和类声明区分引用类型和值类型。

传递引用类型时,实际存储的只有一个。访问实例的所有代码都在访问同一个实例。

传递值类型时,每个值类型都是副本。所有代码都在自己的副本上运行。

这可以用一个例子来说明:

struct MyStruct 
{
    string MyProperty { get; set; }
}

void ChangeMyStruct(MyStruct input) 
{ 
   input.MyProperty = "new value";
}

...

// Create value type
MyStruct testStruct = new MyStruct { MyProperty = "initial value" }; 

ChangeMyStruct(testStruct);

// Value of testStruct.MyProperty is still "initial value"
// - the method changed a new copy of the structure.

对于一个班级来说,这将是不同的

class MyClass 
{
    string MyProperty { get; set; }
}

void ChangeMyClass(MyClass input) 
{ 
   input.MyProperty = "new value";
}

...

// Create reference type
MyClass testClass = new MyClass { MyProperty = "initial value" };

ChangeMyClass(testClass);

// Value of testClass.MyProperty is now "new value" 
// - the method changed the instance passed.

类可以是空的-引用可以指向空。

结构是实际值-它们可以为空,但决不能为空。因此,结构总是有一个没有参数的默认构造函数——它们需要一个“起始值”。

其他回答

结构和类别之间的差异:

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

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

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

在.NET中,结构和类声明区分引用类型和值类型。

传递引用类型时,实际存储的只有一个。访问实例的所有代码都在访问同一个实例。

传递值类型时,每个值类型都是副本。所有代码都在自己的副本上运行。

这可以用一个例子来说明:

struct MyStruct 
{
    string MyProperty { get; set; }
}

void ChangeMyStruct(MyStruct input) 
{ 
   input.MyProperty = "new value";
}

...

// Create value type
MyStruct testStruct = new MyStruct { MyProperty = "initial value" }; 

ChangeMyStruct(testStruct);

// Value of testStruct.MyProperty is still "initial value"
// - the method changed a new copy of the structure.

对于一个班级来说,这将是不同的

class MyClass 
{
    string MyProperty { get; set; }
}

void ChangeMyClass(MyClass input) 
{ 
   input.MyProperty = "new value";
}

...

// Create reference type
MyClass testClass = new MyClass { MyProperty = "initial value" };

ChangeMyClass(testClass);

// Value of testClass.MyProperty is now "new value" 
// - the method changed the instance passed.

类可以是空的-引用可以指向空。

结构是实际值-它们可以为空,但决不能为空。因此,结构总是有一个没有参数的默认构造函数——它们需要一个“起始值”。

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

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

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

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

而类数组看起来像这样

指针

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

对于绝大多数应用程序来说,这种差异并不重要,但是,在高性能代码中,这将影响内存中数据的位置,并对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}");
    }

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

结构:

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

类别:

参考类型值存储在堆中存储对动态分配对象的引用构造函数是用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

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