.NET中struct和class之间有什么区别?
在.NET中,有两类类型,引用类型和值类型.
结构是值类型,类是引用类型.
一般的区别是引用类型存在于堆上,并且值类型保持内联,即,无论何处定义了变量或字段.
包含值类型的变量包含整个值类型值.对于结构,这意味着变量包含整个结构及其所有字段.
包含引用类型的变量包含指针或对实际值所在的内存中其他位置的引用.
这有一个好处,首先:
值类型始终包含值
引用类型可以包含空引用,这意味着它们目前根本不引用任何内容
在内部,引用类型被实现为指针,并且知道并且知道变量赋值如何工作,还有其他行为模式:
将值类型变量的内容复制到另一个变量中,将整个内容复制到新变量中,使两者不同.换句话说,在复制之后,对一个的更改不会影响另一个
将引用类型变量的内容复制到另一个变量中,复制引用,这意味着您现在有两个对实际数据的其他位置存储的引用.换句话说,在复制之后,更改一个引用中的数据也会影响另一个引用,但这只是因为你真的只是在同一个数据中查看两个地方
声明变量或字段时,这两种类型的区别如下:
变量:值类型存在于堆栈中,引用类型作为指向堆内存中某个地方的指针存在于实际内存中(尽管请注意Eric Lipperts文章系列:堆栈是实现细节.)
class/struct-field:value类型完全位于类型内部,引用类型位于类型内部,作为指向实际内存所在的堆内存中某处的指针.
每个简短摘要:
仅限课程:
可以支持继承
是引用(指针)类型
引用可以为null
每个新实例都有内存开销
仅限结构:
不能支持继承
是价值类型
按值传递(如整数)
不能有空引用(除非使用Nullable)
每个新实例都没有内存开销 - 除非'盒装'
类和结构:
复合数据类型通常用于包含一些具有某种逻辑关系的变量
可以包含方法和事件
可以支持接口
在.NET中,struct和class声明区分引用类型和值类型.
传递引用类型时,实际只存储了一个.访问该实例的所有代码都访问同一个代码.
传递值类型时,每个都是副本.所有代码都在自己的副本上工作.
这可以通过一个例子来展示:
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.
类可以是空的 - 引用可以指向null.
结构是实际值 - 它们可以为空但从不为空.出于这个原因,结构总是有一个没有参数的默认构造函数 - 它们需要一个'起始值'.
结构和类之间的区别:
结构是值类型,而类是引用类型.
结构存储在堆栈中,而类存储在堆上.
值类型在声明它们的内存中保存它们的值,但引用类型包含对象内存的引用.
在范围丢失后立即销毁的值类型,而引用类型仅在范围丢失后销毁变量.该对象稍后被垃圾收集器破坏.
将struct复制到另一个struct时,会创建该struct的新副本,修改一个struct不会影响另一个struct的值.
将类复制到另一个类时,它只复制引用变量.
两个引用变量都指向堆上的同一个对象.更改为一个变量将影响另一个参考变量.
结构不能有析构函数,但类可以有析构函数.
结构不能有明确的无参数构造函数,而类结构可以不支持继承,但类可以.两者都支持从接口继承.
结构是密封型的.
来自微软在类和结构之间的选择 ......
根据经验,框架中的大多数类型应该是类.但是,在某些情况下,值类型的特征使得使用结构更合适.
✓ 考虑结构而不是类:
如果该类型的实例很小并且通常是短暂的或通常嵌入在其他对象中.
除非类型具有以下所有特征,否则X 避免使用结构:
它在逻辑上表示单个值,类似于原始类型(int,double等).
它的实例大小小于16个字节.
这是不可改变的.(不能改变)
它不必经常装箱.
除了其他答案中描述的所有差异:
结构不能有明确的无参数构造函数,而类可以
结构不能有析构函数,而类可以
结构不能从另一个结构或类继承,而类可以从另一个类继承.(结构和类都可以从接口实现.)
如果您正在阅读解释所有差异的视频,您可以查看第29部分 - C#教程 - C#中的类和结构之间的差异.
类的实例存储在托管堆上.包含'实例的所有变量只是对堆上实例的引用.将对象传递给方法会导致传递的引用副本,而不是对象本身.
结构(技术上,值类型)存储在任何地方,就像原始类型一样.运行时可以随时复制内容,而无需调用自定义的复制构造函数.将值类型传递给方法涉及复制整个值,同样不需要调用任何可自定义的代码.
通过C++/CLI名称可以更好地区分:"ref class"是首先描述的类,"value class"是第二个描述的类.C#使用的关键字"class"和"struct"只是必须学习的东西.
结构与类
结构是一种值类型,因此它存储在堆栈中,但类是引用类型并存储在堆上.
结构不支持继承和多态,但是类支持两者.
默认情况下,所有struct成员都是公共的,但类成员默认是私有的.
由于结构是值类型,因此我们不能将null分配给结构对象,但类不是这种情况.
除了其他答案外,还有一个基本区别值得注意,那就是它在内存中的存储方式。这会对阵列的性能产生重大影响。结构是值类型,因此它们将值存储在它们指向的内存区域中,类是引用类型,因此它们在它们指向的内存区域中引用一个类,实际值存储在其他位置。
通过结构,可以在包含类中分配内存以存储数据。
对于一个类,包含类将只在不同的内存区域中包含一个指向新类的指针。
数组也是如此,因此结构数组在内存中看起来像这样
[struct][struct][struct][struct][struct][struct][struct][struct]
作为一组类的数组看起来像这样
[pointer][pointer][pointer][pointer][pointer][pointer][pointer][pointer]
您感兴趣的实际值实际上并不存储在数组中,而是存储在内存中的其他位置。
对于绝大多数应用程序而言,这种区别并不重要,但是,在高性能代码中,这将影响内存中数据的局部性,并对CPU缓存的性能产生重大影响。在可以/应该使用结构的情况下使用类将大大增加CPU上的高速缓存未命中数。
现代CPU最慢的操作不是处理数字,而是从内存中获取数据,并且一级缓存命中率比从RAM中读取数据快许多倍。
为了使其完整,使用该Equals
方法时存在另一个差异,该方法由所有类和结构继承.
让我们说我们有一个类和一个结构:
class A{ public int a, b; } struct B{ public int a, b; }
在Main方法中,我们有4个对象.
static void Main{ A c1 = new A(), c2 = new A(); c1.a = c1.b = c2.a = c2.b = 1; B s1 = new B(), s2 = new B(); s1.a = s1.b = s2.a = s2.b = 1; }
然后:
s1.Equals(s2) // true s1.Equals(c1) // false c1.Equals(c2) // false c1 == c2 // false
因此,结构适用于类似数字的对象,如点(保存x和y坐标).课程适合其他人.即使2个人有相同的名字,身高,体重......,他们仍然是2个人.
+-----------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ | | Struct | Class | +-----------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+ | Type | Value-type | Reference-type | | Where | On stack / Inline in containing type | On Heap | | Deallocation | Stack unwinds / containing type gets deallocated | Garbage Collected | | Arrays | Inline, elements are the actual instances of the value type | Out of line, elements are just references to instances of the reference type residing on the heap | | Aldel Cost | Cheap allocation-deallocation | Expensive allocation-deallocation | | Memory usage | Boxed when cast to a reference type or one of the interfaces they implement, | No boxing-unboxing | | | Unboxed when cast back to value type | | | | (Negative impact because boxes are objects that are allocated on the heap and are garbage-collected) | | | Assignments | Copy entire data | Copy the reference | | Change to an instance | Does not affect any of its copies | Affect all references pointing to the instance | | Mutability | Should be immutable | Mutable | | Population | In some situations | Majority of types in a framework should be classes | | Lifetime | Short-lived | Long-lived | | Destructor | Cannot have | Can have | | Inheritance | Only from an interface | Full support | | Polymorphism | No | Yes | | Sealed | Yes | When have sealed keyword | | Constructor | Can not have explicit parameterless constructors | Any constructor | | Null-assignments | When marked with nullable question mark | Yes (+ When marked with nullable question mark in C# 8+) | | Abstract | No | When have abstract keyword | | Access Modifiers | public, private, internal | public, protected, internal, protected internal, private protected | +-----------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
好吧,对于初学者来说,结构是通过值而不是通过引用传递的。结构适合于相对简单的数据结构,而从架构的角度来看,通过多态和继承,类具有更大的灵活性。
其他人可能会给您比我更多的细节,但是当我要使用的结构很简单时,我会使用结构。