Hai từ khóa Constructor Chaining
| Từ khóa | Gọi constructor | Cú pháp |
|---|---|---|
| this | Constructor khác cùng class | : this(args) |
| base | Constructor base class (parent) | : base(args) |
Constructor Chaining với this()
Cho phép tái sử dụng logic khởi tạo, tránh duplicate code.
public class Demo
{
public string Name { get; set; }
public int Age { get; set; }
public string Address { get; set; }
// 1. Constructor đầy đủ nhất (chứa logic chính)
public Demo(string name, int age, string address)
{
Console.WriteLine("Full constructor called");
Name = name;
Age = age;
Address = address;
}
// 2. Gọi constructor 3 tham số
public Demo(string name, int age) : this(name, age, "Unknown")
{
Console.WriteLine("2-param constructor called");
}
// 3. Gọi constructor 2 tham số
public Demo(string name) : this(name, 0)
{
Console.WriteLine("1-param constructor called");
}
// 4. Parameterless → gọi 1 tham số
public Demo() : this("Anonymous")
{
Console.WriteLine("Parameterless constructor called");
}
}
class Program
{
static void Main()
{
Console.WriteLine("=== new Demo() ===");
var d1 = new Demo();
Console.WriteLine("\n=== new Demo('John') ===");
var d2 = new Demo("John");
Console.WriteLine("\n=== new Demo('Jane', 25) ===");
var d3 = new Demo("Jane", 25);
Console.WriteLine("\n=== new Demo('Bob', 30, 'NYC') ===");
var d4 = new Demo("Bob", 30, "NYC");
Console.ReadLine();
}
}
Kết quả chạy
=== new Demo() ===
Full constructor called
1-param constructor called
Parameterless constructor called
=== new Demo('John') ===
Full constructor called
2-param constructor called
1-param constructor called
=== new Demo('Jane', 25) ===
Full constructor called
2-param constructor called
=== new Demo('Bob', 30, 'NYC') ===
Full constructor called
Quy tắc Constructor Chaining
- this() hoặc base() phải là statement đầu tiên trong constructor body.
- Không thể dùng cả
this()vàbase()cùng lúc. - Có thể chain nhiều cấp:
A() : this(1) { } → this(int) : this(1,2) { } → this(int,int) { } - Tránh circular chaining (A→B→A) → StackOverflow.
Kết hợp this() và base()
public class Base
{
public Base(int x) { Console.WriteLine($"Base({x})"); }
public Base(int x, int y) { Console.WriteLine($"Base({x},{y})"); }
}
public class Derived : Base
{
// Gọi base(int)
public Derived(int a) : base(a) { }
// Gọi base(int,int)
public Derived(int a, int b) : base(a, b) { }
// Gọi Derived(int,int) → base(int,int)
public Derived(int a, int b, int c) : this(a, b) { }
}
Best Practices
- Constructor "Master": Có nhiều tham số nhất, chứa logic khởi tạo chính.
- Các constructor khác delegate về master qua
this()với default values. - Validation, complex init logic → đặt ở master constructor.
- Cân nhắc Factory Methods thay vì nhiều constructor phức tạp.
// Factory Method Pattern - thay thế nhiều constructor
public class User
{
public string Name { get; private set; }
public string Email { get; private set; }
public int Age { get; private set; }
private User(string name, string email, int age)
{
Name = name; Email = email; Age = age;
}
public static User CreateAdult(string name, string email, int age)
{
if (age < 18) throw new ArgumentException("Must be 18+");
return new User(name, email, age);
}
public static User CreateMinor(string name, string email, int age, string guardian)
{
if (age >= 18) throw new ArgumentException("Must be under 18");
return new User(name, email, age);
}
}
C# 12: Primary Constructors (Class/Struct)
// C# 12 - Primary constructor parameters tự động thành field
public class Service(string name, int timeout = 30, bool retry = true)
{
// name, timeout, retry có sẵn như field private
public void Run() => Console.WriteLine($"{name}: {timeout}s, retry={retry}");
// Constructor phụ vẫn dùng this()
public Service(string name) : this(name, 30, true) { }
}
var s = new Service("API", 60, false);