In C#, Value types and Reference types are the fundamental types of data types, each having different behaviours and usages. These types define where the variables are stored in the memory and how they behave when a value is assigned to them. In this article, we will discuss the difference between Value types and Reference types in C#. But before discussing their differences, we must know about the Value types and Reference types in C#.
What are the Value Types?
Value types are used to store the data in memory on the stack. When a particular value is assigned to the variable, or a value is passed to it as a parameter, a copy of the value is made. This value type inherits from the System.ValueType . Here, each variable has its own copy of data. Value types directly contain the values.
The value types are again divided into two types: predefined or built-in value types and user-defined value types. The predefined types are present in the C# programming language. They are numerical, character and decimal types.
Numerical types are integral and floating types. Integral types are again divided into the short, int, and long. Character types are utilized to store single characters in the stack, and sometimes, they are used to store the Boolean type.
Example:
Let us take an example to illustrate the predefined value types in C#.
using System;
class Program
{
static void Main(string[] args)
{
// Integer types
int intValue = 10;
uint uintValue = 20;
short shortValue = 30;
ushort ushortValue = 40;
long longValue = 50;
ulong ulongValue = 60;
// Floating-point types
float floatValue = 3.14f;
double doubleValue = 3.14159;
decimal decimalValue = 123.456m;
// Boolean type
bool boolValue = true;
// Character type
char charValue = 'A';
// Displaying the values
Console.WriteLine("Integer types:");
Console.WriteLine($"int: {intValue}");
Console.WriteLine($"uint: {uintValue}");
Console.WriteLine($"short: {shortValue}");
Console.WriteLine($"ushort: {ushortValue}");
Console.WriteLine($"long: {longValue}");
Console.WriteLine($"ulong: {ulongValue}");
Console.WriteLine("\nFloating-point types:");
Console.WriteLine($"float: {floatValue}");
Console.WriteLine($"double: {doubleValue}");
Console.WriteLine($"decimal: {decimalValue}");
Console.WriteLine("\nOther types:");
Console.WriteLine($"bool: {boolValue}");
Console.WriteLine($"char: {charValue}");
}
}
Output:
User-defined Value types:
User-defined types are the value types that are created by the user for specific needs. Important user-defined types are structures and enumerations. The 'struct' keyword is used for creating a structure. The keyword 'enum' is used to create the enumerations, and the structures are similar to the classes. Structures contain data members and member functions but these are lighter than class. Enums consist of a set of named constants. It makes the code or program more readable and maintainable.
Example 2:
Let us take another example to illustrate the Structures in C#.
using System;
public struct Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public void Display()
{
Console.WriteLine($"({X}, {Y})");
}
}
class Program
{
static void Main(string[] args)
{
Point p1 = new Point(5, 10);
Point p2 = new Point(-3, 7);
Console.WriteLine("Point 1:");
p1.Display();
Console.WriteLine("Point 2:");
p2.Display();
}
}
Output:
Example 3:
Let us take another example to illustrate the Enumerations in C#.
using System;
public enum DaysOfWeek
{
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
class Program
{
static void Main(string[] args)
{
DaysOfWeek today = DaysOfWeek.Friday;
Console.WriteLine("Today is: " + today);
}
}
Output:
What are Reference Types?
Reference types are used to store the data on the managed heap. Reference types carry a pointer to the location in memory where the actual data is stored. This reference type inherits from the System.Object . When we assign a reference type variable to another variable, it will create a new pointer to the same data instead of making a new copy of the data. There will be many pointers or references referring to the same object in the heap.
These are also divided into two types: built-in reference types or predefined reference types and user-defined reference types.
Built-in reference types:
The built-in reference types again have different types. Some of them are arrays, strings, objects, dictionaries, threads, streams, etc. As we all know, arrays represent the collection of elements that are the same datatype. Strings are the sequence of characters that are immutable in C#. Objects are the base classes for all other types in C#, and they can hold reference types. Streams are a sequence of bytes.
Example:
Let us take an example to demonstrate the predefined reference types in C#.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
class Program
{
static void Main(string[] args)
{
string str = "Hello, world!";
Console.WriteLine("String: " + str);
object obj = new object();
Console.WriteLine("Object: " + obj.GetType());
int[] numbers = { 1, 2, 3, 4, 5 };
Console.WriteLine("Array:");
Console.WriteLine(string.Join(", ", numbers));
List<string> list = new List<string>() { "apple", "banana", "orange" };
Console.WriteLine("List<string>:");
foreach (string item in list)
{
Console.WriteLine(item);
}
Dictionary<int, string> dictionary = new Dictionary<int, string>()
{
{ 1, "One" },
{ 2, "Two" },
{ 3, "Three" }
};
Console.WriteLine("Dictionary<int, string>:");
foreach (var kvp in dictionary)
{
Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
}
Stream stream = new MemoryStream();
Console.WriteLine("Stream: " + stream.GetType());
Thread thread = new Thread(SomeMethod);
Console.WriteLine("Thread: " + thread.GetType());
}
static void SomeMethod()
{
Console.WriteLine("Thread method executed.");
}
}
Output:
User defined reference types:
User defined reference types are classes, interfaces, and delegates. Classes contain the members and member functions. These are used to define the objects, which have properties and behaviour. Interfaces define a contract that must implement the classes. Delegates represent the references to methods.
Example:
Let us take an example to demonstrate user defined reference types in C#.
using System;
// Define an interface for logging
public interface ILogger
{
void Log(string message);
}
// Define a delegate for math operations
public delegate int MathOperation(int x, int y);
// Define a class representing a Person
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
public void DisplayInfo()
{
Console.WriteLine($"Name: {Name}, Age: {Age}");
}
}
class Program
{
static void Main(string[] args)
{
Person person = new Person("Ramu", 30);
person.DisplayInfo();
ILogger logger = new ConsoleLogger();
logger.Log("Logging message...");
MathOperation add = Add;
int result = add(3, 4);
Console.WriteLine("Result: " + result);
}
static int Add(int x, int y)
{
return x + y;
}
}
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
Output:
Similarities between the value types and reference types in C#:
There are several similarities between the value types and reference types in C#. Some of them are as follows:
- Value types and reference types both have predefined functions and methods, which are used for functionality and can be reusable.
Example for value types which are having methods:
struct Point
{
public int X { get; set; }
public int Y { get; set; }
public void Display(){
Console.WriteLine($"X: {X}, Y: {Y}");
}
}
Example for reference types which are having methods:
class Person{
public string Name { get; set; }
public int Age { get; set; }
public void Display(){
Console.WriteLine($"Name: {Name}, Age: {Age}");
}
}
- Both types can be passed as parameters or arguments to the methods or functions.
- Value types and reference types are used in collections like arrays, lists, and dictionaries, which are used to store the data and manipulate the data.
- Both types are nullable.
- Value types and reference types will implement interfaces. Structs from the value types and classes from the reference types will implement interfaces, which are used to implement and define methods and member functions.
- Both types have the default values. For the value types, 0 is the default value for integers, 0.0 is the default value for doubles, and false is the default value for the Boolean. Some of the reference types, like classes, have null as default values; arrays also have the null value as the default.
Example:
public interface IShape{
double Area { get; }
}
public struct Square : IShape{
public double Side { get; set; }
public double Area => Side * Side;
}
public class Circle : IShape{
public double Radius { get; set; }
public double Area => Math.PI * Radius * Radius;
}
static void Main(string[] args){
Square square = new Square { Side = 5 };
Circle circle = new Circle { Radius = 3 };
Console.WriteLine($"Square area: {square.Area}");
Console.WriteLine($"Circle area: {circle.Area}");
}
Example:
int valueTypeDefault = 0;
string referenceTypeDefault = null;
int[] arrayDefault = null;
- Both can be used as the return for the methods and functions. Methods can able to return value types and as well as the reference types also.
- Value types and reference types have the constructions. Structs from the value types can have the constructor for initiating the variables and classes of reference types have the constructors.
Differences between the value types and reference types in C#:
There are several differences between the value types and reference types in C#. Some of them are as follows:
| Feature Value Types | Reference Types | |
|---|---|---|
| Memory Allocation | The data related to value types are allocated on the stack. These are small and short-lived objects. | The reference types are allocated on the heap. These are for larger objects with long lifetimes. |
| Copying | Changes to the copy do not affect the original. | Multiple references can point to the same object. |
| Definition | A value type holds a data value within its own memory space. | A reference type holds a pointer to another memory location that holds the data. |
| Default initialization | Zero or Null | Null |
| Conversion between types | Implicit or explicit | Implicit or explicit |
| Inheritance | Do not support the inheritance. | Reference types will support the inheritance. |
| Memory Management | Managed automatically by the runtime, stack memory is automatically deallocated when the method exits. | Requires garbage collection for deallocation. Heap memory is reclaimed by the garbage collector when no longer referenced. |
| Boxing/Unboxing | Value types are boxed when treated as objects, incurring performance overhead. | No boxing/unboxing, as they're reference types by default. |
| Performance | These are generally faster due to stack allocation, which will reduce the overhead of heap management. | These are a little slower due to the heap allocation and garbage collection. |
| Examples | Int, float, struct, enum, bool, etc. | Class, interface, array, string, etc. |
Conclusion:
In conclusion, this article is about the value and reference types in C#. In this article, the usages of the value types and reference types are explained in detail.
Value types in C# are stored in the stack, whereas the reference types are stored in a heap. Value types will represent the distinct values where reference types hold references to memory locations where the actual data is stored. Value types are faster due to stack allocation where, whereas the reference types are heap allocation. Both value and reference types can be nullable using the ? modifier . Only reference types can directly participate in inheritance.