C# data types are categorized into two main categories: primitive types and
  non-primitive types. Primitive types are the most basic types that are built
  into the C# language, while non-primitive types are types that are created by
  the programmer. 
  Primitive types include bool, byte, char, decimal, double, float, int, long,
  sbyte, short, uint, ulong, and ushort. 
  Non-primitive types include arrays, classes, delegates, enums, interfaces, and
  structures. 
  When using data types in C#, it's important to know the range and limitations
  of each type. For example, the byte type can only hold values from 0 to 255,
  while the int type can hold values from -2,147,483,648 to 2,147,483,647. 
  The following are the most common datatypes in C# their memory range: 
- bool: Represents a Boolean value, which can be either true or false. The System.Boolean class is used to represent this datatype. It takes up 1 byte of memory: true or false.
 - byte: Represents an unsigned 8-bit integer. The System.Byte class is used to represent this datatype. It takes up 1 byte of memory: 0 to 255.
 - sbyte: Represents a signed 8-bit integer. The System.SByte class is used to represent this datatype. It takes up 1 byte of memory: –128 to 127.
 - char: Represents a Unicode character. The System.Char class is used to represent this datatype. It takes up 2 bytes of memory: Unicode characters.
 - short: Represents a signed 16-bit integer. The System.Int16 class is used to represent this datatype. It takes up 2 bytes of memory: –32768 to 32767.
 - ushort: Represents an unsigned 16-bit integer. The System.UInt16 class is used to represent this datatype. It takes up 2 bytes of memory: 0 to 65535.
 - int: Represents a signed 32-bit integer. The System.Int32 class is used to represent this datatype. It takes up 4 bytes of memory: –2147483648 to 2147483647.
 - uint: Represents an unsigned 32-bit integer. The System.UInt32 class is used to represent this datatype. It takes up 4 bytes of memory: 0 to 4294967295.
 - long: Represents a signed 64-bit integer. The System.Int64 class is used to represent this datatype. It takes up 8 bytes of memory: –9223372036854775808 to 9223372036854775807.
 - ulong: Represents an unsigned 64-bit integer. The System.UInt64 class is used to represent this datatype. It takes up 8 bytes of memory: 0 to 18446744073709551615.
 - float: Represents a single-precision floating-point number. The System.Single class is used to represent this datatype. It takes up 4 bytes of memory: –1.5x10-45 to 3.4 x x1038.
 - double: Represents a double-precision floating-point number. The System.Double class is used to represent this datatype. It takes up 8 bytes of memory: –5.0x10-324 to 1.7x10308.
 - decimal: Represents a decimal number with 28 significant digits. The System.Decimal class is used to represent this datatype. It takes up 16 bytes of memory: 1.0x10-28 to 7.9x1028.
 
  Let's take a look at some examples of how to use these data types in C#:
  
// Example of primitive types
bool isTrue = true;
byte b = 255;
char c = 'A';
decimal d = 1.23m;
double dbl = 3.14;
float f = 3.14f;
int i = 42;
long l = 123456789L;
sbyte sb = 127;
short s = 32767;
uint ui = 4294967295;
ulong ul = 18446744073709551615;
ushort us = 65535;
// Example of non-primitive types
int[] arr = { 1, 2, 3 };
string str = "Hello World";
object obj = new object();
  In this example, we declare variables of different data types and assign them
  values. We also declare an array of integers, a string, and an object. 
  In conclusion, understanding C# data types is crucial for creating effective
  and efficient programs. By using the appropriate data type for each variable,
  you can ensure that your program runs smoothly and without errors.
