## Datatypes and Operators

data types are provided in the `System` namespace. All of them, however, have a C# alias. These aliases are keywords in the C# language

### The integral types

The default value of all integral types is 0. All of these types define two constants called `MinValue` and `MaxValue`, which provide the minimum and maximum value of the type.

Integral literals, which are numbers that appear directly in code (such as 0, -42, and so on), can be specified as decimal, hexadecimal, or binary literals. Decimal literals do not require any suffix. Hexadecimal literals are prefixed with `0x` or `0X`, and binary literals are prefixed with `0b` or `0B`. An underscore (`_`) can be used as a digit separator with all numeric literals.

``````int dec = 32;
int hex = 0x2A;
int bin = 0b_0010_1010;``````

An integral value without any suffix is inferred by the compiler as `int`. To indicate a long integer, use `l` or `L` for a signed 64-bit integer and `ul` or `UL` for an unsigned 64-bit integer.

### The floating-point types

The default value for floating-point types is 0. These types also define two constants called `MinValue` and `MaxValue` that provide the minimum and maximum value of the type. However, these types also provide constants that represent not-a-number (`System.Double.NaN`) and infinity (`System.Double.NegativeInfinity` and `System.Double.PositiveInfinity`)

``````var a = 42.99;//double
float b = 19.50f;
System.Double c = -1.23;``````

### The decimal type

The `decimal` type can represent up to 28 decimal places or 128 bits. is important to note that the `decimal` type minimizes errors during rounding but does not eliminate the need for rounding. For instance, the result of the operation `1m / 3 * 3` is not 1 but `0.9999999999999999999999999999`. On the other hand, `Math.Round(1m / 3 * 3)` yields the value 1`.`

``````decimal a = 42.99m;
var b = 12.45m;
System.Decimal c = 100.75M;``````

### The char type

16 bits

``````char a = 'A';
char b = '\x0065';
char c = '\u15FE';``````

### The string type

A string is an array of characters. In C#, the type for representing a string is called `string` and is an alias for the .NET `System.String`. You can use any of these two types interchangeably. Internally, a string contains a read-only collection of `char` objects. This makes strings immutable, which means that you cannot change a string but need to create a new one every time you want to modify the content of an existing string. Strings are not null-terminated (unlike other languages such as C++) and can contain any number of null characters (`'\0'`).

``````string s1;                       // unitialized
string s2 = null;                // initialized with null
string s3 = String.Empty;        // empty string
string s4 = "hello world";       // initialized with text
var s5 = "hello world";
System.String s6 = "hello world";
char[] letters = { 'h', 'e', 'l', 'l', 'o'};
string s7 = new string(letters); // from an array of chars
char c = s4;  // OK
s4 = 'H';     // error
var s8 = s6.Remove(5);       // hello
var s9 = s6.ToUpper();       // HELLO WORLD``````

formats

``````int i = 42;
string s1 = "This is item " + i.ToString();
string s2 = string.Format("This is item {0}", i);
string s3 = \$"This is item {i}";
string s4 = @"\b\w+\b";``````

### The object type

The `object` type is the base type for all other types in C#, even though you do not specify this explicitly, as we will see in the following chapters. The `object` keyword in C# is an alias for the .NET `System.Object` type. You can use these two interchangeably.

`GetType()` method, which is not virtual and which returns a `System.Type` object with information about the type of the current instance.

`Equals()`  behavior is different for reference and value types. for reference types, this method performs reference equality; this means it checks whether the two variables point to the same object on the heap. For value types, it performs value equality; this means that the two variables are of the same type and that the public and private fields of the two objects are equal.

The default value of a variable of the `object` type is `null`

### Reference types and value types

value types All user-defined types declared as structures (with the `struct` keyword) are value types. Although all types are implicitly derived from the `object`, type value types do not support explicit inheritance
Value types are typically stored on the stack in memory

``````int a = 20;
DateTime dt = new DateTime(2019, 12, 25);
int a = 20;
int b = a;  // b is 20
a = 42;     // a is 42, b is 20``````

reference type does not contain the value directly but a reference to a memory location where the actual value is stored. The built-in data types `object` and `string` are reference types. Arrays, interfaces, delegates, and any user-defined type defined as a class are also called reference types

### Nullable types

Reference types have the default value `null`, which indicates that a variable is not assigned to the instance of any object. Value types do not have such an option. However, there are cases when no value is a valid value for a value type too. To represent such cases, you can use a nullable type.
A nullable type is an instance of System.Nullable, a generic value type that can represent the values of an underlying T type, which can only be a value type, as well as an additional null value.

``````Nullable<int> a;
Nullable<int> b = null;
Nullable<int> c = 42;
int? a;
int? b = null;
int? c = 42;``````

You can use the `HasValue` property to check whether a nullable type object has a value, and `Value` to access the underlying value:

``````if (c.HasValue)
Console.WriteLine(c.Value);``````
``````string? s1 = null; // OK, nullable type
string s2 = null;  // error, non-nullable type``````
• You assign values to a nullable type object the same way you would assign to the underlying type.
• You can use the `GetValueOrDefault()` method to get either the assigned value or the default value of the underlying type if no value is assigned.
• Boxing is performed on the underlying type. If the nullable type object has not assigned any value, the result of boxing is a `null` object.
• You can use the null-coalescing operator, `??`, to access the value of the object of a nullable type (for example, `int d = c ?? -1;`).

### Array

``````int[] arr1;
int[] arr2 = null;
int[] arr3 = new int;
int[] arr4 = new int[] { 1, 1, 2, 3, 5, 8 };
int[] arr5 = new int { 1, 1, 2, 3, 5, 8 };
int[] arr6 = { 1, 1, 2, 3, 5, 8 };
foreach(int element in arr6)
Console.WriteLine(element);``````
``````int[,] arr1;
arr1 = new int[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } };
int[,] arr2 = null;
int[,] arr3 = new int[2,3];
int[,] arr4 = new int[,] { { 1, 2, 3 }, { 4, 5, 6 } };
int[,] arr5 = new int[2,3] { { 1, 2, 3 }, { 4, 5, 6 } };
int[,] arr6 = { { 1, 2, 3 }, { 4, 5, 6 } };``````
``````int[][] arr1;
int[][] arr2 = null;
int[][] arr3 = new int[];
arr3 = new int;
arr3 = new int[] { 1, 1, 2, 3, 5, 8 };
int[][] arr4 = new int[][]
{
new int[] { 1, 2, 3 },
new int[] { 1, 1, 2, 3, 5, 8 }
};
int[][] arr5 =
{
new int[] { 1, 2, 3 },
new int[] { 1, 1, 2, 3, 5, 8 }
};
int[][,] arr6 = new int[][,]
{
new int[,] { { 1, 2}, { 3, 4 } },
new int[,] { {11, 12, 13}, { 14, 15, 16} }
};``````

### Type Conversion

``````string s = "example";
object o = s;          // implicit conversion
string r = (string)o;  // explicit conversion``````
``````public readonly struct fancyint
{
public fancyint(int value)
{
this.value = value;
}
public static implicit operator int(fancyint v) => v.value;
public static explicit operator fancyint(int v) => new fancyint(v);
public override string ToString() => \$"{value}";
}
fancyint a = new fancyint(42);
int i = a;                 // implicit conversion
fancyint b = (fancyint)i;  // explicit conversion``````
``````DateTime dt1 = DateTime.Parse("2019.08.31");
DateTime.TryParse("2019.08.31", out DateTime dt2);
int i1 = int.Parse("42");          // successful, i1 = 42
int i2 = int.Parse("42.15");       // error, throws exception
int.TryParse("42.15", out int i3); // error, returns false,
// i3 = 0``````

### Operators

#### The null-conditional operators

The null-conditional operator has two forms: `?.` (also known as the Elvis operator) to apply member access and `?[]` to apply element access for an array. These operators apply the operation to their operand if and only if that operand is not `null`. Otherwise, the result of applying the operator is also `null`

``````if(a is null)
a = b;
//or
a??=b;``````