Variables and Data Types
Think of a variable as a labeled box: the label is the name, and the box holds the data. Choosing the right size and type of box keeps your data safe and efficient.
Variable Declaration and Initialization
C# is a strongly typed language, so you must specify a type when declaring a variable (or use var to let the compiler infer it):
int age;
age = 25;
string name = "Alice";
double score = 95.5;
You can also declare multiple variables of the same type on one line:
int x = 1, y = 2, z = 3;
Warning: C# does not allow the use of uninitialized local variables; the compiler will raise an error.
Naming Rules
C# enforces strict variable naming rules:
- Must start with a letter or
_; cannot start with a digit - Can only contain letters, digits, and
_ - Case-sensitive (
ageandAgeare different variables) - Cannot use C# keywords (such as
int,class,return)
camelCase and PascalCase
C# has two core naming conventions:
| Identifier Type | Style | Examples |
|---|---|---|
| Local variables, fields | camelCase | studentName, totalCount |
| Methods, classes, properties | PascalCase | CalculateSum, Student |
Tip: camelCase: first word lowercase, subsequent words capitalized; PascalCase: every word capitalized.
int studentAge = 18;
double averageScore = 87.5;
string homeAddress = "Beijing";
Integer Types
C# provides 8 integer types, covering both signed and unsigned:
| Type | Bytes | Range | Suffix |
|---|---|---|---|
sbyte |
1 | -128 ~ 127 | — |
byte |
1 | 0 ~ 255 | — |
short |
2 | -32,768 ~ 32,767 | — |
ushort |
2 | 0 ~ 65,535 | — |
int |
4 | -2,147,483,648 ~ 2,147,483,647 | — |
uint |
4 | 0 ~ 4,294,967,295 | U |
long |
8 | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 | L |
ulong |
8 | 0 ~ 18,446,744,073,709,551,615 | UL |
Tip: Unlike Java, C# has unsigned integer types (byte, ushort, uint, ulong). Note that C#'s byte is unsigned, while the signed version is sbyte.
Example
sbyte sb = -100;
byte b = 200;
short s = -30000;
ushort us = 60000;
int i = 100000;
uint ui = 3000000000U;
long l = 9000000000000000000L;
ulong ul = 18000000000000000000UL;
Console.WriteLine($"sbyte: {sb}");
Console.WriteLine($"byte: {b}");
Console.WriteLine($"short: {s}");
Console.WriteLine($"ushort: {us}");
Console.WriteLine($"int: {i}");
Console.WriteLine($"uint: {ui}");
Console.WriteLine($"long: {l}");
Console.WriteLine($"ulong: {ul}");
sbyte: -100
byte: 200
short: -30000
ushort: 60000
int: 100000
uint: 3000000000
long: 9000000000000000000
ulong: 18000000000000000000
Floating-Point Types
| Type | Bytes | Precision | Range (approx.) | Suffix | Use Case |
|---|---|---|---|---|---|
float |
4 | 7 digits | +/-1.5x10^-45 ~ +/-3.4x10^38 | f |
Graphics, games |
double |
8 | 15-16 digits | +/-5.0x10^-324 ~ +/-1.7x10^308 | d (default) |
Scientific computing |
decimal |
16 | 28-29 digits | +/-1.0x10^-28 ~ +/-7.9x10^28 | m |
Financial amounts |
Warning: Decimal literals are double by default. You must add a suffix when assigning to float or decimal, otherwise the compiler will raise an error.
float f = 3.14f;
double d = 3.14;
decimal m = 3.14m;
Console.WriteLine($"float: {f}");
Console.WriteLine($"double: {d}");
Console.WriteLine($"decimal: {m}");
float: 3.14
double: 3.14
decimal: 3.14
Tip: decimal is designed for financial calculations and avoids binary floating-point errors. For example, 0.1 + 0.2 is not exactly 0.3 with double, but it is exact with decimal.
bool Type
bool has only two values: true and false, occupying 1 byte.
Warning: Unlike C, C#'s bool cannot implicitly convert to or from integers. if(1) is illegal; you must write if(true) or if(x != 0).
bool isReady = true;
bool isEmpty = false;
Console.WriteLine($"isReady: {isReady}");
Console.WriteLine($"isEmpty: {isEmpty}");
isReady: True
isEmpty: False
char Type
C#'s char is a 2-byte Unicode character, not a 1-byte ASCII character like in C.
char ch1 = 'A';
char ch2 = '\u4e2d';
Console.WriteLine($"ch1: {ch1}");
Console.WriteLine($"ch2: {ch2}");
Console.WriteLine($"ch1 code: {(int)ch1}");
Console.WriteLine($"ch2 code: {(int)ch2}");
ch1: A
ch2: 中
ch1 code: 65
ch2 code: 20013
Tip: char uses single quotes 'A', while string uses double quotes "A" — they are completely different types.
string Type
string is a reference type representing an immutable sequence of Unicode characters.
string greeting = "Hello";
string name = "World";
string message = greeting + ", " + name + "!";
Console.WriteLine(message);
Console.WriteLine($"Length: {message.Length}");
Hello, World!
Length: 13
Warning: string is a reference type, and its default value is null (not an empty string ""). Accessing a null string will throw a NullReferenceException.
var Implicit Typing
C# 3.0 introduced the var keyword, which lets the compiler infer the type from the initial value:
var count = 42;
var price = 9.99m;
var label = "hello";
var flag = true;
Console.WriteLine(count.GetType().Name);
Console.WriteLine(price.GetType().Name);
Console.WriteLine(label.GetType().Name);
Console.WriteLine(flag.GetType().Name);
Int32
Decimal
String
Boolean
Warning: var does not mean "any type" — the variable type is determined at compile time and must be initialized. The following is illegal:
var x;
var x = null;
Tip: Use var when type names are long or the type is obvious from context. Avoid overusing it, as it can reduce readability.
sizeof — Checking Type Size
sizeof returns the number of bytes a type occupies. It can be used directly for primitive types; other types require an unsafe context.
Example
Console.WriteLine($"sbyte: {sizeof(sbyte)} bytes");
Console.WriteLine($"byte: {sizeof(byte)} bytes");
Console.WriteLine($"short: {sizeof(short)} bytes");
Console.WriteLine($"ushort: {sizeof(ushort)} bytes");
Console.WriteLine($"int: {sizeof(int)} bytes");
Console.WriteLine($"uint: {sizeof(uint)} bytes");
Console.WriteLine($"long: {sizeof(long)} bytes");
Console.WriteLine($"ulong: {sizeof(ulong)} bytes");
Console.WriteLine($"float: {sizeof(float)} bytes");
Console.WriteLine($"double: {sizeof(double)} bytes");
Console.WriteLine($"decimal: {sizeof(decimal)} bytes");
Console.WriteLine($"char: {sizeof(char)} bytes");
Console.WriteLine($"bool: {sizeof(bool)} bytes");
sbyte: 1 bytes
byte: 1 bytes
short: 2 bytes
ushort: 2 bytes
int: 4 bytes
uint: 4 bytes
long: 8 bytes
ulong: 8 bytes
float: 4 bytes
double: 8 bytes
decimal: 16 bytes
char: 2 bytes
bool: 1 bytes
const Constants
Use const to declare compile-time constants whose values cannot be changed. They must be initialized at declaration:
const double Pi = 3.14159265358979;
const int MaxRetry = 3;
const string AppName = "MyApp";
Console.WriteLine($"Pi = {Pi}");
Console.WriteLine($"MaxRetry = {MaxRetry}");
Console.WriteLine($"AppName = {AppName}");
Pi = 3.14159265358979
MaxRetry = 3
AppName = MyApp
Warning: const names typically use PascalCase. The value must be determinable at compile time and cannot be a variable or method call result.
Tip: If you need a runtime-determined "constant", use a readonly field instead.
Type Default Values
Every type has a default value when no initial value is assigned:
| Type | Default Value |
|---|---|
sbyte / byte / short / ushort / int / uint / long / ulong |
0 |
float |
0.0f |
double |
0.0d |
decimal |
0.0m |
char |
'\0' |
bool |
false |
string |
null |
| Any reference type | null |
Example
int defaultInt = default;
bool defaultBool = default;
char defaultChar = default;
string defaultString = default;
double defaultDouble = default;
Console.WriteLine($"int: [{defaultInt}]");
Console.WriteLine($"bool: [{defaultBool}]");
Console.WriteLine($"char: [{(int)defaultChar}]");
Console.WriteLine($"string: [{defaultString}]");
Console.WriteLine($"double: [{defaultDouble}]");
int: [0]
bool: [False]
char: [0]
string: []
double: [0]
Tip: The default keyword can obtain the default value of any type and is especially common in generics: default(T).
Value Types vs. Reference Types — Introduction
C# types fall into two broad categories:
| Category | Storage | Assignment Behavior | Typical Types |
|---|---|---|---|
| Value type | Stack (usually) | Copies the value | int, bool, char, decimal, struct, enum |
| Reference type | Heap | Copies the reference (address) | string, class, object, arrays |
int a = 10;
int b = a;
b = 20;
Console.WriteLine($"a = {a}, b = {b}");
string s1 = "hello";
string s2 = s1;
s2 = "world";
Console.WriteLine($"s1 = {s1}, s2 = {s2}");
a = 10, b = 20
s1 = hello, s2 = world
Warning: s1 did not become "world" because string is immutable — s2 = "world" does not modify the original object but makes s2 point to a new one. Value type assignment copies the actual value, while reference type assignment copies the reference. However, string's immutability makes it behave like a value type.
❓ FAQ
var and dynamic?var determines the type at compile time and is type-safe; dynamic resolves the type at runtime, has no compile-time type checking, performs worse, and is more error-prone.decimal better than double for monetary calculations?decimal uses decimal storage, so 0.1 can be represented exactly; double uses binary storage, where 0.1 cannot be represented exactly, leading to cumulative rounding errors.string a value type or a reference type?string is a reference type, but due to its immutability, assignment exhibits value semantics — modifying one variable does not affect another.const and readonly?const is a compile-time constant that must be assigned at declaration and is implicitly static; readonly is a runtime constant that can be assigned in a constructor and may differ per instance.📖 Summary
- C# is strongly typed; variables must declare a type or use
varfor inference - Local variables use camelCase; methods and classes use PascalCase
- There are 8 integer types (including unsigned);
intis the most commonly used - Use
decimalfor money,doublefor scientific computing,floatfor graphics boolcannot implicitly convert to or from integers;charis a 2-byte Unicode typevarrequires initialization, and the type is determined at compile timeconstdefines compile-time constants (PascalCase);readonlydefines runtime constants- The
defaultkeyword obtains the default value of any type - Value type assignment copies the value; reference type assignment copies the reference
📝 Exercises
- Declare an
intvariableageset to your age and astringvariablenameset to your name, then output both - Compute
0.1 + 0.2usingfloat,double, anddecimalrespectively, and compare whether the results exactly equal0.3 - Use
sizeofto print the byte sizes ofint,double,char, andbool - Declare a
const double Pi = 3.14159265and calculate the area of a circle with radius 5, then output the result - Use the
defaultkeyword to obtain and output the default values ofint,bool,char, andstring



