В чем разница между struct и class in.NET?

в чем разница между struct и class в .NET?

18 ответов


в .NET существует две категории типов,ссылка типа и типы значений.

структуры типы значений и классы ссылка типа.

общая разница в том, что ссылка типа живет на куче, и a тип значения живет inline, то есть везде, где определена ваша переменная или поле.

переменная, содержащая тип значения содержит весь тип значения значение. Для структуры это означает, что переменная содержит всю структуру со всеми ее полями.

переменная, содержащая ссылка типа содержит указатель, или ссылка в другое место в памяти, где находится фактическое значение.

Это имеет одно преимущество, для начала:

  • типы значений всегда содержит значение
  • ссылка типа может содержать null-ссылка, что означает, что они вообще ни на что не ссылаются на данный момент

внутри ссылка типаs реализованы как указатели, и зная, что, и зная, как работает назначение переменных, существуют другие поведенческие шаблоны:

  • копирование содержимого тип значения переменная в другую переменную, копирует всю содержимое в новую переменную, что делает эти два различных. Другими словами, после копирования изменения одного не повлияют на другое
  • копирование содержимого ссылка типа переменная в другую переменную, копирует ссылку, что означает, что теперь у вас есть две ссылки на то же самое где-то хранение фактических данных. Другими словами, после копирования изменение данных в одной ссылке будет влиять и на другую, но только потому, что вы просто глядя на одни и те же данные в обоих местах

когда вы объявляете переменные или поля, вот как отличаются два типа:

  • переменной: тип значения живет на стеке, ссылка типа живет в стеке как указатель где-то в памяти кучи, где живет фактическая память (хотя Примечание Эрик серия статьи Lipperts: стек-это деталь реализации.)
  • класс/структуру struct-поле: тип значения живет полностью внутри типа,ссылка типа живет внутри типа как указатель на место в памяти кучи, где живет фактическая память.

краткое описание каждого:

Классы Всего:

  • может поддерживать наследования
  • это ссылка (указатель) типа
  • ссылка может быть null
  • есть памяти на новый экземпляр

Структуры Только:

  • не может поддерживать наследование
  • типы значений
  • передаются по значению (как целые числа)
  • Не может быть нулевая ссылка (если не используется значение Nullable)
  • не имеют накладных расходов памяти на новый экземпляр-если только 'boxed'

оба класса и структуры:

  • являются составными типами данных, обычно используемыми для хранения нескольких переменных, которые имеют некоторую логическую связь
  • может содержать методы и события
  • может поддерживать интерфейсы

в .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.

классы не могут быть ничем - ссылка может указывать на null.

структуры являются фактическим значением - они могут быть пустыми, но никогда не нулевыми. По этой причине структуры всегда имеют конструктор по умолчанию без параметров - им нужно "начальное значение".


в дополнение ко всем различиям, описанным в других ответах:

  1. структуры не могут иметь явный конструктор без параметров в то время как класс может
  2. структуры не может быть деструкторов, тогда как класс можно
  3. структуры не может наследовать из другой структуры или класса, А класс может наследовать от другого класса. (Как структуры, так и классы могут реализовываться из интерфейса.)

Если вы после видео, объясняющего все различия, вы можете проверить часть 29-учебник по C# - разница между классами и структурами в C#.


экземпляры классов хранятся в управляемой куче. Все переменные, "содержащие" экземпляр, являются просто ссылкой на экземпляр в куче. Передача объекта методу приводит к передаче копии ссылки, а не самого объекта.

структуры (технически, типы значений) хранятся везде, где они используются, подобно примитивному типу. Содержимое может быть скопировано средой выполнения в любое время и без вызова настраиваемого конструктора копирования. Передача значения тип метода включает копирование всего значения, опять же без вызова настраиваемого кода.

различие сделано лучше именами C++/CLI: "ref class" - это класс, как описано во-первых, "value class" - это класс, как описано во-вторых. Ключевые слова "class" и "struct", используемые C#, просто должны быть изучены.


от Microsoft выбор между Class и Struct ...

Как правило, большинство типов в рамках должно быть занятия. Однако существуют ситуации, когда характеристики типа значения делают его более подходящим для использования структуры.

рассмотрим структуру вместо класса:

  • если экземпляры типа малы и обычно недолговечны или обычно встроены в другие объекты.

X избегайте структуры если типа все из следующих характеристики:

  • логически представляет одно значение, аналогичное примитивным типам (int, double и т. д.).
  • размер экземпляра до 16 байт.
  • она неизменна. (нельзя изменить)
  • это не придется часто боксировал.

разница между стойками и классами -

  • структуры типа, тогда как классы являются ссылочным типом.
  • структуры хранятся в стеке, тогда как классы хранятся на кучи.
  • типы значений сохраняют свое значение в памяти, где они объявлены, но тип ссылки содержит ссылку на память объекта.
  • типы значений уничтожены немедленно после того как объем потерян тогда как ссылочный тип только переменная destroy после того, как область потеряна. Этот объект позже уничтожается сборщиком мусора.
  • когда вы копируете struct в другую структуру, новая копия этой структуры gets created modified of one struct не повлияет на значение другая структура.
  • когда вы копируете класс в другой класс, он копирует только ссылочная переменная.
  • обе опорные переменные указывают на один и тот же объект на куча. Изменение одной переменной повлияет на другую ссылочную переменную.
  • структуры не могут иметь деструкторы, но классы могут иметь деструкторы.
  • структуры не могут иметь явных конструкторов без параметров а структуры class can не поддерживают наследование, но классы поддерживают. Оба поддержка наследования от интерфейса.
  • структуры закрытого типа.

структура против класс

структура является типом значения, поэтому она хранится в стеке, но класс является ссылочным типом и хранится в куче.

структуры не поддерживают наследование и полиморфизм, но класс поддерживает.

по умолчанию все члены структуры являются открытыми, но члены класса по умолчанию являются частными.

поскольку структура является типом значения, мы не можем назначить null объекту struct, но это не для класса.


просто, чтобы сделать его полным, есть еще одно отличие при использовании 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 человека.


Ну, для начала, а структура передается по значению, а не по ссылке. Структуры хороши для относительно простых структур данных, в то время как классы имеют гораздо больше гибкости с архитектурной точки зрения через полиморфизм и наследование.

другие, вероятно, могут дать вам больше деталей, чем я, но я использую структуры, когда структура, которую я собираюсь, проста.


помимо основного различия спецификатора доступа и нескольких упомянутых выше, я хотел бы добавить некоторые из основных различий, включая несколько из упомянутых выше, с образцом кода с выходом, который даст более четкое представление о ссылке и значении

структуры:

  • являются типами значений и не требуют выделения кучи.
  • выделение памяти отличается и хранится в стеке
  • полезно для небольших данных структуры
  • влияет на производительность, когда мы передаем значение методу, мы передаем всю структуру данных, и все передается в стек.
  • конструктор просто возвращает само значение структуры (обычно во временном месте в стеке), и это значение затем копируется по мере необходимости
  • каждая переменная имеет свою собственную копию данных, и операции над одной не могут повлиять на другую.
  • не поддерживает указанное Пользователем наследование, и они неявно наследуются от типа object

класс:

  • ссылка типа
  • хранится в куче
  • сохранить ссылку на динамически выделяемый объект
  • конструкторы вызываются с помощью оператора 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: 10

Метод Внутренней Структуры Внутри метода значение объекта Struct: 20

после вызова метода значение объекта Struct: 10

начальное значение объекта класса: 10

Метод Внутреннего Класса Внутри метода значение класса Object: 20

после вызова метода значение объекта класса: 20

здесь вы можете четко видеть разницу между вызовом по значению и вызовом по ссылке.


  1. события, объявленные в классе, имеют свой + = и -= доступ, автоматически заблокированный через блокировку (это), чтобы сделать их потокобезопасными (статические события заблокированы на типе класса). События, объявленные в структуре, не имеют автоматически заблокированного доступа += и -=. Блокировка (this) для структуры не будет работать, так как вы можете заблокировать только выражение ссылочного типа.

  2. создание экземпляра структуры не может вызвать сборку мусора (если конструктор прямо или косвенно создает экземпляр ссылочного типа), тогда как создание экземпляра ссылочного типа может вызвать сборку мусора.

  3. структура всегда имеет встроенный конструктор по умолчанию.

    class DefaultConstructor
    {
        static void Eg()
        {
            Direct     yes = new   Direct(); // Always compiles OK
            InDirect maybe = new InDirect(); // Compiles if constructor exists and is accessible
            //...
        }
    }
    

    Это означает, что структура всегда материализуемых в то время как класс может не быть, поскольку все его конструкторы могут быть частными.

    class NonInstantiable
    {
        private NonInstantiable() // OK
        {
        }
    }
    
    struct Direct
    {
        private Direct() // Compile-time error
        {
        }
    }
    
  4. структура не может иметь деструктор. Деструктор-это просто переопределение объект.Завершить в маскировке, а структуры, являющиеся типами значений, не подлежат сбору мусора.

    struct Direct
    {
        ~Direct() {} // Compile-time error
    }
    class InDirect
    {
        ~InDirect() {} // Compiles OK
    }
    
    And the CIL for ~Indirect() looks like this:
    
    .method family hidebysig virtual instance void
            Finalize() cil managed
    {
      // ...
    } // end of method Indirect::Finalize
    
  5. структура неявно запечатана, класс-нет.
    Структура не может быть абстрактной, класс может.
    Структура не может вызвать : base() в своем конструкторе, тогда как класс без явного базового класса может.
    Структура не может расширить другой класс, класс может.
    Структура не может объявлять защищенные члены (например, поля, вложенные типы) a класс может.
    Структура не может объявлять абстрактные члены функции, абстрактный класс может.
    Struct может не объявлять виртуальные функции, класс.
    Структура не может объявлять запечатанные члены функции, класс может.
    Структура не может объявлять члены функции override, класс может.
    Единственным исключением из этого правила является то, что структура может переопределить виртуальные методы системы.Object, viz, Equals (), GetHashCode () и ToString ().


Как упоминалось ранее: классы являются ссылочным типом, а структуры-типами значений со всеми последствиями.

в качестве большого пальца руководства по разработке рамок правил рекомендует использовать структуры вместо классов, если:

  • он имеет размер экземпляра менее 16 байт
  • он логически представляет одно значение, подобное примитивным типам (int,double и т. д.)
  • он незыблем
  • его не нужно будет упаковывать часто

чтобы добавить к другим ответам, есть одно фундаментальное различие, которое стоит отметить, и именно так оно хранится в памяти. Это может оказать существенное влияние на производительность массивов. Структуры-это типы значений, поэтому они хранят значение в области памяти, на которую они указывают, классы-ссылочные типы, поэтому они ссылаются на класс в области памяти, на которую они указывают, фактическое значение хранится в другом месте.

  • С помощью структуры память выделяется в пределах содержащий класс для хранения данных.
  • С классом содержащий класс будет содержать только указатель на новый класс в другой области памяти.

это также верно для массивов, поэтому массив структур выглядит так в памяти

[struct][struct][struct][struct][struct][struct][struct][struct]

где в виде массива классов выглядит так

[pointer][pointer][pointer][pointer][pointer][pointer][pointer][pointer]

фактические значения, которые вас интересуют, фактически не хранятся в массиве, а в другом месте память.

для подавляющего большинства приложений эта разница на самом деле не имеет значения, однако в высокопроизводительном коде это повлияет на локальность данных в памяти и окажет большое влияние на производительность кэша процессора. Использование классов, когда вы могли/должны были использовать структуры, значительно увеличит количество пропусков кэша на ЦП.

самая медленная вещь, которую делает современный процессор, - это не хруст чисел, это извлечение данных из памяти, а хит кэша L1-много раз быстрее, чем чтение данных из ОЗУ.


структуры являются фактическим значением - они могут быть пустыми, но никогда не null

это правда, однако также обратите внимание, что начиная с .NET 2 структуры поддерживают нулевую версию, А C# предоставляет некоторый синтаксический сахар, чтобы упростить его использование.

int? value = null;
value  = 1;

есть один интересный случай головоломки "класс против структуры", когда вам нужно вернуть несколько результатов из метода: выберите, какой использовать. Если вы знаете историю ValueTuple-вы знаете, что ValueTuple (struct) был добавлен, потому что он должен быть более эффективным, чем Кортеж (класс). Но что это значит в цифрах? Два теста: один-struct / class, который имеет 2 поля, другой-struct / class, который имеет 8 полей (с размером более 4-class должен стать более эффективным, чем структура в терминах процессорных ТИКов, но, конечно, следует учитывать и нагрузку GC).

P.S. Еще один ориентир для конкретного случая "sturct или класс с коллекциями" есть:https://stackoverflow.com/a/45276657/506147

BenchmarkDotNet=v0.10.10, OS=Windows 10 Redstone 2 [1703, Creators Update] (10.0.15063.726)
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233540 Hz, Resolution=309.2586 ns, Timer=TSC
.NET Core SDK=2.0.3
  [Host] : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT
  Clr    : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2115.0
  Core   : .NET Core 2.0.3 (Framework 4.6.25815.02), 64bit RyuJIT


            Method |  Job | Runtime |     Mean |     Error |    StdDev |      Min |      Max |   Median | Rank |  Gen 0 | Allocated |
------------------ |----- |-------- |---------:|----------:|----------:|---------:|---------:|---------:|-----:|-------:|----------:|
  TestStructReturn |  Clr |     Clr | 17.57 ns | 0.1960 ns | 0.1834 ns | 17.25 ns | 17.89 ns | 17.55 ns |    4 | 0.0127 |      40 B |
   TestClassReturn |  Clr |     Clr | 21.93 ns | 0.4554 ns | 0.5244 ns | 21.17 ns | 23.26 ns | 21.86 ns |    5 | 0.0229 |      72 B |
 TestStructReturn8 |  Clr |     Clr | 38.99 ns | 0.8302 ns | 1.4097 ns | 37.36 ns | 42.35 ns | 38.50 ns |    8 | 0.0127 |      40 B |
  TestClassReturn8 |  Clr |     Clr | 23.69 ns | 0.5373 ns | 0.6987 ns | 22.70 ns | 25.24 ns | 23.37 ns |    6 | 0.0305 |      96 B |
  TestStructReturn | Core |    Core | 12.28 ns | 0.1882 ns | 0.1760 ns | 11.92 ns | 12.57 ns | 12.30 ns |    1 | 0.0127 |      40 B |
   TestClassReturn | Core |    Core | 15.33 ns | 0.4343 ns | 0.4063 ns | 14.83 ns | 16.44 ns | 15.31 ns |    2 | 0.0229 |      72 B |
 TestStructReturn8 | Core |    Core | 34.11 ns | 0.7089 ns | 1.4954 ns | 31.52 ns | 36.81 ns | 34.03 ns |    7 | 0.0127 |      40 B |
  TestClassReturn8 | Core |    Core | 17.04 ns | 0.2299 ns | 0.2150 ns | 16.68 ns | 17.41 ns | 16.98 ns |    3 | 0.0305 |      96 B |

код:

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;
            }
        }
    }
}

каждая переменная или поле примитивного типа значения или типа структуры содержит уникальный экземпляр этого типа, включая все его поля (public и private). Напротив, переменные или поля ссылочных типов могут содержать null или ссылаться на объект, хранящийся в другом месте, на который также может существовать любое количество других ссылок. Поля структуры будут храниться в том же месте, что и переменная или поле этого типа структуры, которое может быть либо в стеке, либо часть из еще один объект в куче.

создание переменной или поля типа примитивного значения создаст его со значением по умолчанию; создание переменной или поля типа структуры создаст новый экземпляр, создав все поля в нем способом по умолчанию. Создание нового экземпляр ссылочного типа начнется с создания всех полей в нем по умолчанию, а затем запуск дополнительного кода в зависимости от типа.

копирования одного переменная или поле примитивного типа в другое будет копировать значение. Копирование одной переменной или поля типа структуры в другое будет копировать все поля (public и private) первого экземпляра в последний экземпляр. Копирование одной переменной или поля ссылочного типа в другой приведет к тому, что последняя будет ссылаться на тот же экземпляр, что и первая (если таковая имеется).

важно отметить, что в некоторых языках, таких как C++, семантическое поведение типа не зависит от того, как оно хранится, но это не так .Сеть. Если тип реализует семантику изменяемых значений, копирование одной переменной этого типа в другую копирует свойства первого экземпляра в другой экземпляр, на который ссылается второй, и использование члена второго для изменения приведет к изменению этого второго экземпляра, но не первого. Если тип реализует изменяемую ссылочную семантику, копирование одной переменной в другую и использование члена второй для изменения объекта повлияет на объект, на который ссылается первая переменные; типы с неизменяемой семантикой не допускают мутации, поэтому семантически не имеет значения, создает ли копирование новый экземпляр или создает другую ссылку на первый.

в .NET типы значений могут реализовать любую из вышеперечисленных семантик при условии, что все их поля могут делать то же самое. Однако ссылочный тип может реализовать только изменяемую ссылочную семантику или неизменяемую семантику; типы значений с полями изменяемых ссылочных типов ограничены либо реализация изменяемой ссылочной семантики, либо странная гибридная семантика.


+-----------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+
|                       |                                                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            | Mutable                                                                                              | Should be immutable                                                                               |
| Population            | Majority of types in a framework should be classes                                                   | In some situations                                                                                |
| Lifetime              | Long-lived                                                                                           | Short-lived                                                                                       |
| Destructor            | Can't have                                                                                           | Can have                                                                                          |
| Inheritence           | Only from an interdace                                                                               | Full-support                                                                                      |
| Polymotphism          | 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                                                                                               |
| Abstract              | No                                                                                                   | When have abstract keyword                                                                        |
| Access Modifiers      | public, private, internal                                                                            | public, protected, internal, protected internal, private protected                                |
+-----------------------+------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------+