C# categorizes data types into two main categoreis: value types and reference types
Value types include: byte, short/char, int, long, float, double, decimal, enum, struct
Reference types include: string, object, interface, delegate, array
Value types pass copies of values, while reference types pass memory addresses
When two variables have identical values, modifying one doesn't affect the other
When two variables reference the same address, modifying one affects both
object.ReferenceEquals(first, second) // Check if objects are the same instance
Converting from larger to smaller types requires explicit casting, while converting from smaller to larger types happens implicitly
All assignment and arithmetic operations can trigger automatic type conversion
Implicit conversion always transforms from smaller to larger types
Converting char to int yields ASCII values, and vice versa
Note: ASCII is a numeric encoding system for letters and symbols
Operations between identical types don't trigger automatic conversion
For example: 3/5 returns 0 because both 3 and 5 are integers, the result remains int type, not automatically converting to double
char and short have the same size but different ranges, preventing direct assignment between them
char ranges from 0 to 65535, while short ranges from -32768 to 32767
Some types require specific suffixes during assignment
decimal uses M suffix
float uses f suffix
long uses L suffix
Example:
decimal price = 3.14M
Enumerations represent a finite set of named values
Enums offer better readability than primitive types and better performance than strings
Enums are ideal for representing fixed categories like gender, nationality, or regions
Five access modifiers define visibility scopes:
private - accessible only within the declaring class
protected - accessible within the declaring class and derived classes
public - accessible from any location
internal - accessible within the current assembly
protected internal - accessible within the current assemb or derived classes
Access modifiers control accessibility and usage rights
Classes default to internal, while class members default to private
Properties encapsulate fields, ensuring data validity through get and set accessors
Get and set are essentially methods: get triggers during retrieval, set triggers during assignment
public void SetIdentifier(int value)
{
identifier = value;
}
public int GetIdentifier()
{
return identifier;
}
public int Identifier { get => identifier; set => identifier = value; } // Lambda expression syntax (not recommended)
public int Identifier { get; set; } = 10; // Auto-property with initializer
String formatting with placeholders
string greeting = "hello";
string target = "world";
Console.WriteLine(String.Format("{0}, {1}!", greeting, target));
When outputting statements with multiple variables, continuous concatenation becomes cumbersome. String.Format with placeholders solves this
A more convenient syntax exists:
Console.WriteLine($"{greeting}, {target}!");
Available in newer C# versions
Constructors initialize class instances
Constructors can have different access modifiers than their classes
Constructor parameters can have default values: parameters with defaults are optional, without defaults are required
When a class has constructors, object instantiation must provide corresponding parameters
public class Product
{
int productId;
public Product(int id)
{
this.productId = id; // Use 'this' to distinguish between parameter and field
}
}
Product item = new Product(101); // Provide required int parameter
Otherwise, compilation fails
public class Product
{
int productId;
public Product(int id = 0)
{
this.productId = id;
}
}
Product item = new Product(); // Optional parameter allows instantiation without arguments
Method parameters can also have default values
public void DisplayMessage(string text = "default")
{
Console.WriteLine(text + " processed");
}
Code refactoring: reuse existing code for common functionality
public Employee(int empId, string empName = "Unknown") // Initialize employee with ID and name
{
this.EmployeeId = empId;
this.EmployeeName = empName;
}
public Employee(int empId, string empName, string department) : this(empId, empName)
{
this.Department = department; // Reuse base constructor, add department
}
// Method overloading example
public int Calculate(int x, int y)
{
return x + y;
}
public int Calculate(int x, int y, int z)
{
return Calculate(x, y) + z;
}
throw new InvalidOperationException("Custom error message");
Indexers
Indexers enable objects to be accessed using collection-like syntax
public class DataCollection
{
private string[] items = new string[3];
public string this[int index]
{
get { return items[index]; }
set { items[index] = value; }
}
}
static void Main()
{
DataCollection collection = new DataCollection();
collection[0] = "First item";
collection[1] = "Second item";
collection[2] = "Third item";
for (int i = 0; i < 3; i++)
{
Console.WriteLine(collection[i]);
}
Console.ReadLine();
}
Indexers are syntactically similar to properties but provide array-like access to objects