C# struct/class Differences
struct Direct{ //...}
class InDirect{ //...}
Events are locked? Exist on stack or heap? Can cause garbage collection? Meaning of this? Always has a default constructor? Default construction triggers static construction? Can be null? Use with the as operator? Can be locked? Can have a destructor? Default field layout? Can be a volatile field? Can have synchronized methods? Can be pointed to? Can be stackalloc'd? Can be sizeof'd? How to initialize fields? Inheritance differences? Equals behavior Events are locked?
Events declared in a class have their += and -= access automatically locked via a lock(this) to make them thread safe (static events are locked on the typeof the class). Events declared in a struct do not have their += and -= access automatically locked. A lock(this) for a struct would not work since you can only lock on a reference type expression.
Exist on stack or heap?
Value type local instances are allocated on the stack. Reference type local instances are allocated on the heap.
Can cause garbage collection?
Creating a struct instance cannot cause a garbage collection (unless the constructor directly or indirectly creates a reference type instance) whereas creating a reference type instance can cause garbage collection.
Meaning of this?
In a class, this is classified as a value, and thus cannot appear on the left hand side of an assignment, or be used as a ref/out parameter. For example:
class Indirect{ //... public void Method(Indirect that) { RefParameter(ref this); // compile-time error OutParameter(out this); // compile-time error this = that; // compile-time error } //...}
In a struct, this is classified as an out parameter in a constructor and as a ref parameter in all other function members. Thus it is possible to modify the entire structure by assigning to this or passing this as a ref/out parameter. For example:
struct Direct{ //... public void Reassign(Direct that) { RefParameter(ref this); // compiles ok OutParameter(out this); // compiles ok this = that; // compiles ok } //...}
Furthermore, you can reassign a whole struct even when the struct contains readonly fields!
struct Direct{ public Direct(int value) { Field = value; } public void Reassign(Direct that) { RefParameter(ref this); // compiles ok OutParameter(out this); // compiles ok this = that; // compiles ok } public readonly int Field;}class Show{ static void Main() { Direct s = new Direct(42); Console.WriteLine(s.Field); // writes 42 s.Reassign(new Direct(24)); Console.WriteLine(s.Field); // writes 24 }}
Note however that when you call a method on a readonly value-type field, the method call is made on a copy of the field.
struct Direct{ // as above}class Caller{ public void Method() { Console.WriteLine(d.Field); // writes 42 d.Reassign(new Direct(24)); Console.WriteLine(d.Field); // writes 42! } private readonly Direct d = new Direct(42); }class Show{ static void Main() { Caller c = new Caller(); c.Method(); }}
Always have a default constructor?
A struct always has a built-in public default constructor.
class DefaultConstructor{ static void Eg() { Direct yes = new Direct(); // always compiles ok InDirect maybe = new InDirect(); // compiles if c'tor exists and is accessible //... }}
This means that a struct is always instantiable whereas a class might not be since all its constructors could be private.
class NonInstantiable{ private NonInstantiable() // ok { }}struct Direct{ private Direct() // compile-time error { }}
Default construction triggers static constructor?
A structs static constructor is not triggered by calling the structs default constructor. It is for a class.
struct Direct{ static Direct() { Console.WriteLine("This is not written"); }}class NotTriggered{ static void Main() { Direct local = new Direct(); }}
Can be null?
A struct in