Tiến hóa qua các phiên bản C#
| Phiên bản | Cách gán default value |
| C# 1.0 - 5.0 | Chỉ trong constructor |
| C# 6.0+ | Property initializer (inline) |
| C# 9.0+ | Init-only properties + with expression |
| C# 12+ | Primary constructors |
C# 5.0 và trước: Constructor
public class Demo
{
public string FirstName { get; set; }
public int Age { get; set; }
public Demo()
{
FirstName = "DefaultName";
Age = 18;
}
}
C# 6.0+: Property Initializer (Inline)
public class Demo
{
// Gán giá trị trực tiếp tại property
public string FirstName { get; set; } = "DefaultName";
public int Age { get; set; } = 18;
public List Tags { get; set; } = new List();
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
// Sử dụng
var d = new Demo();
Console.WriteLine(d.FirstName); // DefaultName
Console.WriteLine(d.Age); // 18
C# 9.0+: Init-only Properties (Immutable)
public class Person
{
// Chỉ set được lúc khởi tạo (object initializer)
public string FirstName { get; init; } = "Default";
public string LastName { get; init; } = "User";
public int Age { get; init; } = 18;
}
// Sử dụng
var p = new Person { FirstName = "John", Age = 25 };
// p.FirstName = "Jane"; // ❌ Compile error: init-only
// With-expression (C# 9+) - tạo copy với thay đổi
var p2 = p with { Age = 26 }; // p không đổi, p2 mới với Age=26
C# 12+: Primary Constructors
// Parameters tự động thành fields/private properties
public class Service(string name, int timeout = 30, bool retry = true)
{
// name, timeout, retry dùng được trong class
public void Run() => Console.WriteLine($"{name}: {timeout}s, retry={retry}");
// Có thể expose qua property
public string Name => name;
public int Timeout { get; } = timeout;
public bool Retry { get; } = retry;
}
var s = new Service("API"); // timeout=30, retry=true
var s2 = new Service("DB", 60, false);
Required Properties (C# 11+)
public class Config
{
// BẮT BUỘC phải cung cấp khi khởi tạo
public required string ConnectionString { get; init; }
public required int Port { get; init; }
// Optional với default
public int Timeout { get; init; } = 30;
}
// Sử dụng
var c = new Config
{
ConnectionString = "Server=...",
Port = 5432
// Timeout = 30 (default)
};
// ❌ Compile error nếu thiếu required
// var bad = new Config { Port = 5432 };
So sánh các cách
| Cách | Cú pháp | Mutable? | Validation? | Phiên bản |
| Constructor | Trong body ctor | Có | Dễ dàng | C# 1.0+ |
| Property Initializer | = value | Có | Khó (chỉ const/simple) | C# 6.0+ |
| Init-only | { get; init; } = value | Không (sau init) | Trong init accessor | C# 9.0+ |
| Required | required | Tùy init/set | Compile-time check | C# 11+ |
| Primary Constructor | Class(params) | Tùy design | Trong body | C# 12+ |
Best Practices
- C# 6+: Dùng property initializer cho default values đơn giản.
- Immutable data: Dùng
init + required + record.
- Complex validation: Constructor hoặc Factory Method.
- Dependencies: Primary constructor (C# 12) cho DI-friendly classes.
- Collections: Khởi tạo
= new List<T>() tránh null reference.
Ví dụ tổng hợp Modern C#
// C# 12 - Record với primary constructor, required, init
public record UserProfile(
required string Username,
required string Email,
string DisplayName = "Anonymous", // Optional với default
int Reputation = 0, // Optional với default
DateTime CreatedAt = default // Default = DateTime.MinValue
)
{
// Validation trong primary constructor body
public UserProfile
{
if (string.IsNullOrWhiteSpace(Username))
throw new ArgumentException("Username required");
if (!Email.Contains("@"))
throw new ArgumentException("Invalid email");
}
}
// Sử dụng
var user = new UserProfile("john_doe", "john@test.com", "John", 100);
var user2 = user with { Reputation = 150 }; // Immutable update