26. Modern C# Features
Level: Beginner to Intermediate
Goal: Understand modern C# features in simple words before using them in real projects.
- What modern C# features are
- Why records reduce repeated code
- What pattern matching does
- What init and required properties mean
- When to learn each feature
C# keeps improving.
Modern C# features help us write:
- Less code
- Cleaner code
- Safer code
- More readable code
Do not worry about memorizing all features today. First understand where each feature is useful.
Quick Definitions
- Tuple - Return multiple values from method as grouped package
- Record - Simple data class with automatic equality, ToString, hashing
- Pattern matching - Check object properties/values with
is,switch initproperty - Set value only during object creation, cannot change afterrequiredproperty - Compiler forces this value to be provided- Primary constructor - Constructor parameters become field initializers automatically
- Deconstruction - Unpack tuple into separate variables
- Immutable - Cannot be changed after creation
- Syntactic sugar - Shorter syntax for common pattern
- Nullable - Can be null or have value
What We Will Learn
| Feature | Simple Meaning |
|---|---|
| Tuple | Return more than one value from a method |
| Record | Create simple data objects with less code |
| Pattern matching | Check object shape or value clearly |
init property | Set a value only during object creation |
required property | Force important values to be provided |
| Primary constructor | Shorter constructor syntax |
Tuples
A tuple can hold multiple values together.
Example: A method can return pass status, grade, and percentage.
static (bool passed, string grade, double percentage) CalculateResult(int mark)
{
bool passed = mark >= 35;
string grade = mark >= 90 ? "A+" :
mark >= 75 ? "A" :
mark >= 35 ? "Pass" : "Fail";
return (passed, grade, mark);
}
var result = CalculateResult(86);
Console.WriteLine(result.passed);
Console.WriteLine(result.grade);
Console.WriteLine(result.percentage);
You can also split the tuple into variables.
var (passed, grade, percentage) = CalculateResult(86);
Console.WriteLine($"{grade} - {percentage}");
Use tuples when the returned values are small and closely related.
Records
A record is a simple way to create a data object.
public record StudentDto(int Id, string Name, string ClassName);
This one line creates a data type with:
- Properties
- Constructor
- Useful
ToString() - Value-based comparison
Example:
var student1 = new StudentDto(1, "Sahasra", "10th");
var student2 = new StudentDto(1, "Sahasra", "10th");
Console.WriteLine(student1 == student2); // True
Console.WriteLine(student1);
Records are useful for:
- API responses
- DTOs
- Read-only data
- Small data models
Record with With Expression
Records are usually used as immutable data.
If you need a changed copy, use with.
var student = new StudentDto(1, "Sahasra", "10th");
var promotedStudent = student with { ClassName = "11th" };
Console.WriteLine(student.ClassName); // 10th
Console.WriteLine(promotedStudent.ClassName); // 11th
The original object is not changed.
Pattern Matching
Pattern matching helps us write cleaner condition checks.
Example:
static string GetResultMessage(int marks)
{
return marks switch
{
>= 90 => "Excellent",
>= 75 => "Very good",
>= 35 => "Pass",
_ => "Fail"
};
}
Console.WriteLine(GetResultMessage(82));
This is easier to read than many if-else blocks.
Object Pattern Matching
You can check object properties directly.
public class Student
{
public string Name { get; set; } = "";
public double Percentage { get; set; }
public bool FeesPaid { get; set; }
}
static string GetStudentStatus(Student student)
{
return student switch
{
{ Percentage: >= 90, FeesPaid: true } => "Top student and fees clear",
{ Percentage: >= 35, FeesPaid: true } => "Passed and fees clear",
{ Percentage: >= 35, FeesPaid: false } => "Passed but fees pending",
_ => "Needs attention"
};
}
Init Properties
init means a property can be set only when creating the object.
public class Student
{
public int Id { get; init; }
public string Name { get; init; } = "";
public string ClassName { get; set; } = "";
}
var student = new Student
{
Id = 1,
Name = "Sahasra",
ClassName = "10th"
};
student.ClassName = "11th"; // allowed
// student.Id = 2; // not allowed after creation
Use init for values that should not change later, like ID.
Required Properties
required tells C# that a value must be given when creating the object.
public class Teacher
{
public required string Name { get; set; }
public required string Subject { get; set; }
}
var teacher = new Teacher
{
Name = "Anitha",
Subject = "Maths"
};
If Name or Subject is missing, C# shows a compile-time error.
Primary Constructors
Primary constructors make constructor code shorter.
Traditional style:
public class FeeService
{
private readonly string _schoolName;
public FeeService(string schoolName)
{
_schoolName = schoolName;
}
}
Modern style:
public class FeeService(string schoolName)
{
public void PrintSchool()
{
Console.WriteLine(schoolName);
}
}
You will see this more in newer .NET projects.
School Management Example
Use tuple, record, and pattern matching together.
When You'll Use This in SMS
Modern C# simplifies SMS code.
Tuples return multiple values:
// Return pass status, grade, percentage
var (passed, grade, pct) = CalculateStudentResult(marks);
Records simplify data objects:
public record StudentDto(int Id, string Name, string ClassName);
public record FeeDto(int StudentId, decimal Amount, bool Paid);
Pattern matching validates cleanly:
if (student is { ClassName: "10-A", Status: "Active" })
ProcessStudent(student);
init prevents accidental changes:
public record Student
{
public string Name { get; init; } // Set once, never change
}
Real impact: Modern features reduce 50 lines of boilerplate to 5 lines.
Try This Now
- Create tuple returning (status, grade, percentage)
- Deconstruct:
var (pass, grade, pct) = Calculate(85); - Create record:
record Student(int Id, string Name); - Use pattern matching to check student properties
- Compare old class vs new record versions
Modern C# features explained: Tuples, Records, Pattern Matching, init properties, required properties, primary constructors. Video coming soon. Subscribe to NexCoding YouTube for updates.
Common Mistakes
Mistake 1: Using tuples for too much data.
return (id, name, className, section, phone, email, address);
Better: create a class or record.
Mistake 2: Using records for behavior-heavy objects.
public record FeeService();
Better: use class for services.
Mistake 3: Forgetting the default case in switch expressions.
string result = marks switch
{
>= 35 => "Pass"
};
Better:
string result = marks switch
{
>= 35 => "Pass",
_ => "Fail"
};
Best Practices
- Use tuples for small multiple return values.
- Use records for DTOs and simple data.
- Use classes for business logic and services.
- Use pattern matching when it improves readability.
- Always include
_default in switch expressions. - Use
initfor values that should not change. - Use
requiredfor mandatory properties. - Learn modern features slowly and apply them where they make code clearer.
Practice Task
Create a small program that:
- Creates a
recordcalledExamResult. - Stores student name and marks.
- Uses pattern matching to find grade.
- Returns grade and pass status using a tuple.
Quick Revision
- Tuple returns multiple values.
- Record creates simple data objects.
- Pattern matching makes conditions cleaner.
initprotects values after object creation.requiredforces important values.- Primary constructors reduce constructor code.
A tuple is a small group of values. It is useful when a method needs to return more than one value.
A record is a simple data type. It is commonly used for DTOs, API responses, and read-only data.
Use a class for behavior and business logic. Use a record for simple data that mainly stores values.
Pattern matching is a clean way to check values, types, or object properties and return results.
required forces the developer to provide a property value when creating an object.
Use ChatGPT, Claude, or Copilot to go deeper on Modern C# features. Try these prompts:
"Explain C# records with school examples""Explain tuples in simple words with examples""Give me beginner exercises for C# pattern matching""When should I use init and required in C#?"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.