مقدمه

در درس‌های گذشته، یاد گرفتیم که چگونه با استفاده از کلمه‌ی کلیدی new یک شیء بسازیم و سپس در خطوط جداگانه، مقادیر پراپرتی‌های عمومی آن را تنظیم کنیم. این روش کاملاً کارآمد است، اما می‌تواند منجر به کدی طولانی و چندمرحله‌ای شود، به خصوص زمانی که یک شیء پراپرتی‌های زیادی دارد. زبان C# برای ساده‌سازی و افزایش خوانایی این فرآیند، یک سینتکس بسیار قدرتمند و مختصر به نام مقداردهی اولیه شیء (Object Initializer) ارائه می‌دهد. این ویژگی به ما اجازه می‌دهد تا یک شیء را ایجاد و همزمان پراپرتی‌های آن را در یک دستور واحد مقداردهی کنیم.

روش سنتی مقداردهی اولیه اشیاء

بیایید ابتدا روشی را که تا به حال برای ایجاد و مقداردهی یک شیء استفاده می‌کردیم، مرور کنیم. فرض کنید کلاسی به نام Book با چند پراپرتی خودکار داریم:

Copy Icon Program.cs
public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
}

// --- Traditional Initialization ---

// 1. Create the object
Book myBook = new Book();

// 2. Set properties in separate statements
myBook.Title = "The Catcher in the Rye";
myBook.Author = "J.D. Salinger";

این روش کاملاً درست عمل می‌کند، اما عملیات منطقاً واحدِ "ساختن و مقداردهی یک کتاب" در سه خط کد مجزا پخش شده است. اگر تعداد پراپرتی‌ها بیشتر بود، این کد طولانی‌تر نیز می‌شد.

سینتکس مقداردهی اولیه شیء (Object Initializer)

سینتکس مقداردهی اولیه شیء به ما اجازه می‌دهد که پس از فراخوانی new، یک بلوک کد با استفاده از آکولاد {} باز کرده و مقادیر پراپرتی‌های مورد نظر را مستقیماً در آن مشخص کنیم.

Copy Icon Program.cs
// Initialization using an Object Initializer
Book myBook = new Book
{
    Title = "1984",
    Author = "George Orwell"
};

Console.WriteLine($"'{myBook.Title}' by {myBook.Author}");

این سینتکس بسیار مختصرتر و خواناتر است. تمام عملیات در یک دستور واحد انجام می‌شود. در پشت صحنه، کامپایلر ابتدا سازنده‌ی پیش‌فرض و بدون پارامتر کلاس را فراخوانی می‌کند و سپس دستورات مقداردهی پراپرتی‌ها را اجرا می‌کند. این بدان معناست که برای استفاده از مقداردهی اولیه شیء، کلاس شما باید یک سازنده‌ی قابل دسترس و بدون پارامتر داشته باشد (که اگر هیچ سازنده‌ی دیگری تعریف نکرده باشید، کامپایلر به طور خودکار آن را فراهم می‌کند).

استفاده از مقداردهی اولیه با سازنده‌ها

شما می‌توانید سینتکس مقداردهی اولیه شیء را با سازنده‌هایی که پارامتر دارند نیز ترکیب کنید. این کار زمانی مفید است که برخی مقادیر برای ساخت شیء اجباری هستند و باید از طریق سازنده پاس داده شوند، در حالی که پراپرتی‌های دیگر اختیاری هستند و می‌توان آن‌ها را از طریق مقداردهی اولیه تنظیم کرد.

Copy Icon Program.cs
public class Product
{
    // Read-only property set in constructor
    public int ProductId { get; }

    // Optional properties
    public string Name { get; set; }
    public decimal Price { get; set; }

    public Product(int productId)
    {
        this.ProductId = productId;
    }
}

// --- Usage ---
// The constructor is called first, then the object initializer is executed.
Product laptop = new Product(101) 
{ 
    Name = "Laptop", 
    Price = 999.99m 
};

Console.WriteLine($"ID: {laptop.ProductId}, Name: {laptop.Name}, Price: {laptop.Price}");

در این مثال، ProductId یک مقدار اجباری است که باید از طریق سازنده فراهم شود. اما Name و Price اختیاری هستند و می‌توانیم آن‌ها را به راحتی با استفاده از سینتکس مقداردهی اولیه شیء تنظیم کنیم. ترتیب اجرا به این صورت است: ابتدا سازنده Product(101) فراخوانی می‌شود و سپس پراپرتی‌های داخل بلوک آکولاد مقداردهی می‌شوند.

مقداردهی اولیه برای اشیاء تودرتو

قدرت واقعی این سینتکس زمانی مشخص می‌شود که با اشیاء پیچیده و تودرتو کار می‌کنیم. شما می‌توانید برای پراپرتی‌هایی که خودشان از نوع یک کلاس دیگر هستند نیز از مقداردهی اولیه استفاده کنید.

Copy Icon Program.cs
public class Author { public string Name { get; set; } }

public class Book
{
    public string Title { get; set; }
    public Author AuthorInfo { get; set; } // A property that is another object
}

// --- Nested Object Initialization ---
Book anotherBook = new Book
{
    Title = "War and Peace",
    AuthorInfo = new Author { Name = "Leo Tolstoy" } // Initialize nested object
};

Console.WriteLine($"Book '{anotherBook.Title}' was written by {anotherBook.AuthorInfo.Name}.");

در کد بالا، ما یک شیء Book و همزمان شیء Author مربوط به آن را در یک دستور واحد ایجاد و مقداردهی کرده‌ایم. این روش باعث می‌شود کدی که گراف‌های پیچیده‌ای از اشیاء را می‌سازد، بسیار خوانا و اعلانی (declarative) باشد.

مقداردهی اولیه کالکشن‌ها (Collection Initializers)

مفهوم مشابهی برای مقداردهی اولیه‌ی کالکشن‌ها (مانند لیست‌ها و دیکشنری‌ها) نیز وجود دارد که به آن مقداردهی اولیه کالکشن (Collection Initializer) گفته می‌شود. این سینتکس به شما اجازه می‌دهد تا در زمان ایجاد یک کالکشن، عناصر اولیه‌ی آن را نیز مشخص کنید. این موضوع را در فصل مربوط به کالکشن‌ها به تفصیل بررسی خواهیم کرد.

// Collection initializer for a List of strings
var names = new List<string> { "Alice", "Bob", "Charlie" };

// Combining object and collection initializers
var books = new List<Book>
{
    new Book { Title = "Book A", Author = "Author X" },
    new Book { Title = "Book B", Author = "Author Y" }
};