Data types in C#
A variable’s memory size and the kinds of values it can hold are determined by the data types that are defined in C#. In C#, each variable, constant, and array needs to have a data type, which determines the amount of memory allotted and the types of values that can be stored. Every variable and object in C# must have a specified type as the language is tightly typed. Because it incorporates a number of type-safe safeguards, this strong typing encourages robust applications.
Value types, reference types, and pointer types are the three basic categories into which C# data types fall.
Value Types
Data is directly contained in value types. Usually, the program execution stack is where they are kept. Two identical copies of the value are created in memory when a value type variable is assigned to another. System is the source of them.ValueType. When the program leaves their scope, such as when the code block in which they are defined completes running, the memory allotted for value types is released.
Examples of Predefined Value Types:
Integer types: short, ushort, int, uint, long, ulong, sbyte, byte, and so on. Whole numbers are stored in these categories. An example of an aliasing system is the 32-bit signed integer int.Int32.
- You can use int number; to declare an integer variable.
- Compile-time known types’ size in bytes can be obtained using the sizeof operator.
Alias | Type Name | Size (bits) | Range | Default Value |
byte | System.SByte | 8 | -128 to 127 | 0 |
short | System.Int16 | 16 | -32768 to 32767 | 0 |
int | System.Int32 | 32 | −231 to 231−1 | 0 |
long | System.Int64 | 64 | −263 to 263−1 | 0L |
sbyte | System.Byte | 8 | 0 to 255 | 0 |
ushort | System.UInt16 | 16 | 0 to 65535 | 0 |
uint | System.UInt32 | 32 | 0 to 232−1 | 0U |
ulong | System.UInt64 | 64 | 0 to 264−1 | 0UL |
Real floating-point types: Decimal, float, and double. Decimal numbers are stored in these categories. Double has 15–16 digits of precision, whereas float has just 7. A 128-bit high-precision format appropriate for financial applications is decimal. Double-precision is the default for floating-point values; to impose single precision, add f or F (e.g., 1.23f).
Alias | Type Name | Size (bits) | Approximate Range | Precision (Decimal Digits) | Default Value |
---|---|---|---|---|---|
float | System.Single | 32 | ±1.5×10⁻⁴⁵ to ±3.4×10³⁸ | 6–9 | 0.0f |
double | System.Double | 64 | ±5.0×10⁻³²⁴ to ±1.7×10³⁰⁸ | 15–17 | 0.0d |
decimal | System.Decimal | 128 | ±1.0×10⁻²⁸ to ±7.9×10²⁸ | 28–29 | 0.0m |
Boolean type: Bool. True or false are its two possible values. Bool values, in contrast to C and C++, can only be cast directly or implicitly to the object data type. It is frequently applied to logical statements.
Alias | Type Name | Size (bits) | Range | Default Value |
---|---|---|---|---|
bool | System.Boolean | 8 (typically) | true or false | false |
Character type: Char. One Unicode character (16-bit number) can be stored in this type.
Alias | Type Name | Size (bits) | Range | Default Value |
---|---|---|---|---|
char | System.Char | 16 | U+0000 to U+FFFF (Unicode characters) | '\0' (null character |
User-Defined Value Types:
Structures (struct)
: They are value types that store their members directly on the stack and are defined with the struct keyword. Despite being comparable to classes, they do not provide inheritance and are lighter and better suited for tiny data sets.
Enumerations (enum)
: A collection of named constants of an underlying integral numeric type define a value type.
Example
using System;
namespace ValueTypeExample
{
// Define a user-defined Value Type: a struct
// Structs are value types and directly contain their data.
public struct Point
{
public int X;
public int Y;
// Constructor for the struct
public Point(int x, int y)
{
X = x;
Y = y;
}
// Override ToString for better display of the struct's value
public override string ToString()
{
return $"({X}, {Y})";
}
}
class Program
{
static void Main(string[] args)
{
// Declare and initialize a built-in Value Type (int)
// 'numberA' directly holds the value 10.
int numberA = 10;
Console.WriteLine($"Original numberA: {numberA}"); // Output: Original numberA: 10
// Assigning 'numberA' to 'numberB' copies the value.
// 'numberB' now holds its own copy of 10.
int numberB = numberA;
Console.WriteLine($"Original numberB (copy of numberA): {numberB}"); // Output: Original numberB (copy of numberA): 10
// Modifying 'numberB' does NOT affect 'numberA'.
// This demonstrates that 'numberB' is an independent copy.
numberB = 20;
Console.WriteLine($"Modified numberB: {numberB}"); // Output: Modified numberB: 20
Console.WriteLine($"numberA after modifying numberB: {numberA}"); // Output: numberA after modifying numberB: 10
Console.ReadKey(); // Keep console open until a key is pressed
}
}
}
Output
Original numberA: 10
Original numberB (copy of numberA): 10
Modified numberB: 20
numberA after modifying numberB: 10
You can also read Understanding C# Comments & It’s Types With Code Examples
Reference Types
Reference types store a reference (memory address) to the actual data location on the heap rather than the data itself. Both variables point to the same location in memory when a reference type variable is assigned to another; only the reference is transferred.
Examples of Predefined Reference Types:
Object type: object
. This is System’s alias..NET object. All types predefined and user-defined, reference and value types inherit from System either directly or indirectly in C#’s unified type system.Object
. Variables of type object can be allocated values of any kind.
String type: string
. This is System’s alias.string. Strings
are collections of characters that are immutable, meaning that once they are created, their character sequences cannot be altered. The StringBuilder
class is suggested for concatenating strings in order to prevent the creation of new string instances.
Dynamic type: dynamic
.
User-Defined Reference Types
Classes: characterised by the class keyword. They support inheritance and are the most potent data type in C#. Fields, methods, constructors, destructors, properties, indexers, delegates, and events are examples of members found in classes.
Arrays: In C#, classes relate to types, which are kept in a heap and include built-in features for finding and sorting. These are System-type objects.array. Arrays function substantially differently from C++ arrays and are defined differently.
Delegates: types that, like function pointers, securely enclose a method.
Interfaces: A class may implement a set of member declarations. By default, interface members are abstract and public. Multiple interfaces can be implemented by a class.
Example
using System;
namespace ReferenceTypeExample
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
public override string ToString()
{
return $"Name: {Name}, Age: {Age}";
}
}
class Program
{
static void Main(string[] args)
{
Person person1 = new Person("Alice", 30);
Console.WriteLine($"Original person1: {person1}");
Person person2 = person1;
Console.WriteLine($"Original person2 (copy of reference to person1): {person2}");
person2.Age = 31;
person2.Name = "Alicia";
Console.WriteLine($"Modified person2: {person2}");
Console.WriteLine($"person1 after modifying person2: {person1}");
Console.ReadKey(); // Keep console open
}
}
}
Output
Original person1: Name: Alice, Age: 30
Original person2 (copy of reference to person1): Name: Alice, Age: 30
Modified person2: Name: Alicia, Age: 31
person1 after modifying person2: Name: Alicia, Age: 31
You can also read C# .NET Framework: Your Foundation for Windows Development
Pointer Types
The memory address of another type is stored in pointer type variables. In order to preserve type safety and security, C# pointers are only permitted in unsafe code blocks, while having capabilities comparable to those of C or C++ pointers.
// Example using unsafe modifier
using System;
namespace UnsafeCodeApplication
{
class Program
{
static unsafe void Main(string[] args)
{
int var = 20;
int* p = &var; // Declaring a pointer
Console.WriteLine("Data is: {0} ", var);
Console.WriteLine("Address is: {0}", (int)p);
Console.ReadKey();
}
}
}
This code gives an Output like:
main.cs(7,16): error CS0227: Unsafe code requires the `unsafe' command line option to be specified
Compilation failed: 1 error(s), 0 warnings
Type Conversion: Boxing and Unboxing
Value types can be converted to and from object types since System.Object is the root of all C# types.
Boxing: Converting a value type to an object type or interface type that it implements is an implicit process. A value type’s value is copied to the heap-allocated object when it is boxed.
Unboxing: transforming an object type into a value type explicitly. The object instance must be checked, and the value from the instance must then be copied back to the value-type variable.
Common Type System (CTS)
All programming languages that use.NET have their data types standardised by the Common Type System (CTS), which makes communication between them simple and seamless. For example, CTS allows for flexible communication by converting an int in C# and an int in VB.NET to System.Int32. CTS guarantees interoperability between objects written in various.NET languages.
You can also read Structure Of C# Program With Example And It’s Syntax