struct MyStruct{string MyProperty { get; set; }}
void ChangeMyStruct(MyStruct input){input.MyProperty = "new value";}
...
// Create value typeMyStruct 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 typeMyClass testClass = new MyClass { MyProperty = "initial value" };
ChangeMyClass(testClass);
// Value of testClass.MyProperty is now "new value"// - the method changed the instance passed.
class DefaultConstructor{static void Eg(){Direct yes = new Direct(); // Always compiles OKInDirect maybe = new InDirect(); // Compiles if constructor exists and is accessible//...}}
A struct cannot have a destructor. A destructor is just an override of object.Finalize in disguise, and structs, being value types, are not subject to garbage collection.
struct Direct{~Direct() {} // Compile-time error}class InDirect{~InDirect() {} // Compiles OK}
And the CIL for ~Indirect() looks like this:
.method family hidebysig virtual instance voidFinalize() cil managed{// ...} // end of method Indirect::Finalize
A struct is implicitly sealed, a class isn't. A struct can't be abstract, a class can. A struct can't call : base() in its constructor whereas a class with no explicit base class can. A struct can't extend another class, a class can. A struct can't declare protected members (for example, fields, nested types) a class can. A struct can't declare abstract function members, an abstract class can. A struct can't declare virtual function members, a class can. A struct can't declare sealed function members, a class can. A struct can't declare override function members, a class can. The one exception to this rule is that a struct can override the virtual methods of System.Object, viz, Equals(), and GetHashCode(), and ToString().
static void Main(string[] args){//StructmyStruct 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();
//ClassmyClass 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;}}
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}");}
有一个有趣的“class vs struct”难题案例——当你需要从方法返回几个结果时的情况:选择使用哪个。如果你知道ValueTuple的故事——你就会知道ValueTuple(struct)被添加是因为它应该比Tuple(class)更有效。但是它在数字中意味着什么?两个测试:一个是有2个字段的struct/class,另一个是有8个字段的struct/class(在处理器滴答声方面,类应该比struct更有效,但当然GC负载也应该被考虑在内)。
using System;using System.Text;using System.Collections.Generic;using BenchmarkDotNet.Attributes;using BenchmarkDotNet.Attributes.Columns;using BenchmarkDotNet.Attributes.Exporters;using BenchmarkDotNet.Attributes.Jobs;using DashboardCode.Routines.Json;
namespace Benchmark{//[Config(typeof(MyManualConfig))][RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn][ClrJob, CoreJob][HtmlExporter, MarkdownExporter][MemoryDiagnoser]public class BenchmarkStructOrClass{static TestStruct testStruct = new TestStruct();static TestClass testClass = new TestClass();static TestStruct8 testStruct8 = new TestStruct8();static TestClass8 testClass8 = new TestClass8();[Benchmark]public void TestStructReturn(){testStruct.TestMethod();}
[Benchmark]public void TestClassReturn(){testClass.TestMethod();}
[Benchmark]public void TestStructReturn8(){testStruct8.TestMethod();}
[Benchmark]public void TestClassReturn8(){testClass8.TestMethod();}
public class TestStruct{public int Number = 5;public struct StructType<T>{public T Instance;public List<string> List;}
public int TestMethod(){var s = Method1(1);return s.Instance;}
private StructType<int> Method1(int i){return Method2(++i);}
private StructType<int> Method2(int i){return Method3(++i);}
private StructType<int> Method3(int i){return Method4(++i);}
private StructType<int> Method4(int i){var x = new StructType<int>();x.List = new List<string>();x.Instance = ++i;return x;}}
public class TestClass{public int Number = 5;public class ClassType<T>{public T Instance;public List<string> List;}
public int TestMethod(){var s = Method1(1);return s.Instance;}
private ClassType<int> Method1(int i){return Method2(++i);}
private ClassType<int> Method2(int i){return Method3(++i);}
private ClassType<int> Method3(int i){return Method4(++i);}
private ClassType<int> Method4(int i){var x = new ClassType<int>();x.List = new List<string>();x.Instance = ++i;return x;}}
public class TestStruct8{public int Number = 5;public struct StructType<T>{public T Instance1;public T Instance2;public T Instance3;public T Instance4;public T Instance5;public T Instance6;public T Instance7;public List<string> List;}
public int TestMethod(){var s = Method1(1);return s.Instance1;}
private StructType<int> Method1(int i){return Method2(++i);}
private StructType<int> Method2(int i){return Method3(++i);}
private StructType<int> Method3(int i){return Method4(++i);}
private StructType<int> Method4(int i){var x = new StructType<int>();x.List = new List<string>();x.Instance1 = ++i;return x;}}
public class TestClass8{public int Number = 5;public class ClassType<T>{public T Instance1;public T Instance2;public T Instance3;public T Instance4;public T Instance5;public T Instance6;public T Instance7;public List<string> List;}
public int TestMethod(){var s = Method1(1);return s.Instance1;}
private ClassType<int> Method1(int i){return Method2(++i);}
private ClassType<int> Method2(int i){return Method3(++i);}
private ClassType<int> Method3(int i){return Method4(++i);}
private ClassType<int> Method4(int i){var x = new ClassType<int>();x.List = new List<string>();x.Instance1 = ++i;return x;}}}}
+--------------------------------------------------+------+----------------------------------------------+| 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. |+--------------------------------------------------+------+----------------------------------------------+