On this page

Variables, types, and operators in C# 14

14 min read TextCh. 1 — C# Fundamentals

Data types in C#

C# is a strongly typed language: every variable has a type known at compile time. The compiler rejects incompatible operations before the program runs, which eliminates an entire category of bugs.

Value types vs reference types

This is the most important distinction in C#:

Category Types Stored in
Value int, double, bool, char, decimal, struct Stack
Reference string, class, array, object Heap

Value types are copied on assignment. Reference types share the same memory:

// Value type — gets copied
int a = 10;
int b = a;
b = 20;
Console.WriteLine(a); // 10 — unchanged

// Reference type — shares reference
int[] arr1 = { 1, 2, 3 };
int[] arr2 = arr1;
arr2[0] = 99;
Console.WriteLine(arr1[0]); // 99 — changed!

Integer types

C# offers integers of different sizes to optimize memory usage:

byte  min = byte.MinValue;   // 0
byte  max = byte.MaxValue;   // 255
int   i   = int.MaxValue;    // 2,147,483,647
long  l   = long.MaxValue;   // 9,223,372,036,854,775,807

// BigInteger for arbitrarily large numbers
using System.Numerics;
BigInteger huge = BigInteger.Pow(10, 100); // 10^100

Use int by default. Use long if values can exceed 2 billion. Use byte only when memory is critical.

Floating-point types

// Literals with mandatory suffixes
float   lowPrecision  = 1.5f;     // 'f' suffix required
double  midPrecision  = 1.5;      // default is double
decimal highPrecision = 1.5m;     // 'm' suffix required

// Special double values
double infinity = double.PositiveInfinity;
double nan      = double.NaN;
bool   isNan    = double.IsNaN(nan); // true

// Math constants
double pi = Math.PI;   // 3.141592653589793
double e  = Math.E;    // 2.718281828459045

Strings in C#

Strings in C# are immutable: every operation creates a new string. For intensive concatenation, use StringBuilder:

using System.Text;

// Normal strings
string firstName = "David";
string lastName  = "Morales";
string fullName  = firstName + " " + lastName; // creates a new object

// String interpolation — the preferred way
string msg = $"Hello, {firstName}! Today is {DateTime.Now:dddd, MMMM dd yyyy}.";

// Verbatim strings — no escape sequences needed
string path = @"C:\Users\David\Documents\project.cs";

// Raw string literals (C# 11+) — multiline, no escapes
string html = """
    <div class="card">
      <h1>Title</h1>
    </div>
    """;

// StringBuilder for bulk concatenation
var sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
    sb.Append($"Line {i}\n");
}
string result = sb.ToString();

Essential string methods:

string text = "  Hello World  ";
Console.WriteLine(text.Trim());              // "Hello World"
Console.WriteLine(text.ToUpper());           // "  HELLO WORLD  "
Console.WriteLine(text.ToLower());           // "  hello world  "
Console.WriteLine(text.Contains("World"));   // true
Console.WriteLine(text.Replace("World", "C#")); // "  Hello C#  "
Console.WriteLine(text.Split(' ').Length);   // splits into words

// Check for empty/whitespace
string empty = "";
Console.WriteLine(string.IsNullOrEmpty(empty));       // true
Console.WriteLine(string.IsNullOrWhiteSpace("   "));  // true

const and readonly

// const — evaluated at compile time
const double PI        = 3.14159265;
const int    MAX_ITEMS = 100;
const string APP_NAME  = "BemoreLearn";

// readonly — evaluated at runtime (inside classes)
class Config
{
    public readonly string ConnectionString;
    public readonly DateTime StartedAt;

    public Config(string connStr)
    {
        ConnectionString = connStr;
        StartedAt        = DateTime.Now; // can use dynamic values
    }
}

Type conversions

// Implicit conversion (safe, no data loss)
int    integer = 42;
long   large   = integer;   // int → long implicit
double dbl     = integer;   // int → double implicit

// Explicit conversion (cast — may lose data)
double price   = 19.99;
int    truncated = (int)price;  // 19 — truncates decimals

// Parse — string to number (throws exception on failure)
int number = int.Parse("42");
double d   = double.Parse("3.14");

// TryParse — safe version (no exception)
if (int.TryParse("abc", out int result))
{
    Console.WriteLine($"Converted: {result}");
}
else
{
    Console.WriteLine("Conversion failed"); // this runs
}

// Convert — general-purpose conversion
string numStr  = Convert.ToString(123);   // "123"
bool   boolVal = Convert.ToBoolean(1);    // true

Operators

// ── Arithmetic ───────────────────────────────────────
int sum   = 10 + 3;   // 13
int diff  = 10 - 3;   // 7
int prod  = 10 * 3;   // 30
int divI  = 10 / 3;   // 3 (integer division)
int mod   = 10 % 3;   // 1 (modulo/remainder)
double divD = 10.0 / 3; // 3.333...

// Increment/decrement
int x = 5;
Console.WriteLine(x++); // 5 (post-increment: use THEN increment)
Console.WriteLine(++x); // 7 (pre-increment: increment THEN use)

// ── Comparison ──────────────────────────────────────
bool eq   = (5 == 5);  // true
bool neq  = (5 != 3);  // true
bool gt   = (5 > 3);   // true
bool lt   = (3 < 5);   // true
bool gte  = (5 >= 5);  // true
bool lte  = (3 <= 5);  // true

// ── Logical ─────────────────────────────────────────
bool and  = true && false; // false (AND)
bool or   = true || false; // true  (OR)
bool not  = !true;         // false (NOT)

// ── Compound assignment ──────────────────────────────
int n = 10;
n += 5;  // n = 15
n -= 3;  // n = 12
n *= 2;  // n = 24
n /= 4;  // n = 6
n %= 4;  // n = 2

// ── Ternary ──────────────────────────────────────────
int age = 20;
string access = age >= 18 ? "Allowed" : "Denied";

Practice

  1. Types and conversions: Create a program that asks the user for two numbers with Console.ReadLine(), converts them with double.TryParse, sums them, and displays the result formatted as {result:N2}.
  2. Nullable: Declare int? temperature = null. Use ?? to assign 20 as the default value if null and display the result.
  3. StringBuilder: Generate a multiplication table from 1 to 10 using StringBuilder and a for loop.

In the next lesson we will cover control flow structures (if/else, switch expressions, loops) and method definitions in C#.

Use decimal for money
Never use float or double for monetary values. Float and double have floating-point precision errors (0.1 + 0.2 != 0.3). Always use decimal for prices, balances, and any financial calculation.
const vs readonly
const is evaluated at compile time and only accepts primitive types. readonly is evaluated at runtime and can be assigned in the constructor. Use const for class-level constants; use readonly for values that depend on the environment.
Nullable reference types
With <Nullable>enable in the .csproj, the compiler analyzes whether you can access a string variable without checking for null first. Take advantage of this feature to eliminate NullReferenceException before runtime.
// ── Integer types ─────────────────────────────────────
byte  b  = 255;           // 0 to 255
sbyte sb = -128;          // -128 to 127
short s  = 32_767;        // underscore as visual separator
int   i  = 2_147_483_647;
long  l  = 9_223_372_036_854_775_807L;

// ── Floating-point types ─────────────────────────────
float   f = 3.14f;        // 7 digits of precision
double  d = 3.14159265;   // 15-17 digits of precision
decimal m = 19.99m;       // 28-29 digits — ideal for money

// ── Other primitive types ────────────────────────────
bool   active = true;
char   letter = 'A';      // single quotes for char
string name   = "David";  // immutable text string

// ── Type inference with var ──────────────────────────
var age   = 30;           // inferred as int
var price = 99.99m;       // inferred as decimal
var greet = "Hello";      // inferred as string

Console.WriteLine($"int max: {int.MaxValue}");
Console.WriteLine($"decimal max: {decimal.MaxValue}");