TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 550 subscribers
Post #639 223
🏗 استفاده در Entityها و Value Objectها (با یک نکته مهم)

کم‌کم استفاده از Primary Constructorها را در Entityها و Value Objectها نیز آغاز کردم؛ مخصوصاً در جاهایی که می‌خواهید وجود برخی پارامترها را هنگام ساخت شیء اجباری کنید.
public class Order(Guid customerId, Money total)
{
public Guid Id { get; } = Guid.NewGuid();
public Guid CustomerId { get; } = customerId;
public Money Total { get; } = total;
public OrderStatus Status { get; private set; } = OrderStatus.Pending;
public DateTime CreatedAt { get; } = DateTime.UtcNow;

public void Confirm()
{
if (Status != OrderStatus.Pending)
{
throw new InvalidOperationException(
$"Cannot confirm order in {Status} status.");
}

Status = OrderStatus.Confirmed;
}
}

در این طراحی، هیچ راهی برای ایجاد یک Order بدون customerId یا total وجود ندارد.
ءPrimary Constructor این محدودیت را مستقیماً در سطح تعریف Type نمایش می‌دهد.
اما یک تفاوت مهم با مثال سرویس‌ها وجود دارد:
در اینجا پارامترهای Primary Constructor را به Propertyها اختصاص داده‌ایم:
public Guid CustomerId { get; } = customerId;

این نکته اهمیت زیادی دارد و مستقیماً به بزرگ‌ترین چالش Primary Constructorها منتهی می‌شود.

⚠️ مشکلی که نزدیک بود باعث شود هرگز از آن استفاده نکنم

دلیل اصلی مقاومت اولیه من همین موضوع بود.
پارامترهای Primary Constructor در واقع فیلدهای readonly نیستند.
زمانی که مستقیماً از پارامترهای Primary Constructor در بدنه کلاس استفاده می‌کنید، کامپایلر آن‌ها را به‌عنوان یک متغیر قابل تغییر (mutable) Capture می‌کند.
هیچ فیلد readonly مخفی‌ای در پشت صحنه ایجاد نمی‌شود.
به همین دلیل می‌توانید به‌اشتباه مقدار آن‌ها را تغییر دهید:
public class OrderService(
IOrderRepository orderRepository,
ILogger<OrderService> logger)
{
public async Task<Order?> GetOrderAsync(Guid id)
{
logger.LogInformation("Fetching order {OrderId}", id);

return await orderRepository.GetByIdAsync(id);
}

public void SomeOtherMethod()
{
// This compiles. No warning. No error.
orderRepository = null!;
logger = null!;
}
}

این کد بدون هیچ Warning یا Error کامپایل می‌شود.
در صورتی که اگر از Constructor سنتی و فیلدهای private readonly استفاده می‌کردید، کامپایلر بلافاصله جلوی این کار را می‌گرفت.
اما در Primary Constructorها سکوت می‌کند.
🔒 اگر به Immutability نیاز دارید

در صورتی که تضمین Immutable بودن برای شما اهمیت دارد، می‌توانید پارامترها را به فیلدهای readonly اختصاص دهید:
public class OrderService(
IOrderRepository orderRepository,
ILogger<OrderService> logger)
{
private readonly IOrderRepository _orderRepository = orderRepository;
private readonly ILogger<OrderService> _logger = logger;

public async Task<Order?> GetOrderAsync(Guid id)
{
_logger.LogInformation("Fetching order {OrderId}", id);

return await _orderRepository.GetByIdAsync(id);
}
}

اما در این حالت بخش زیادی از مزیت Primary Constructor از بین می‌رود.
دوباره به تعریف فیلدها و Assignmentها بازمی‌گردید؛ فقط با سینتکسی متفاوت.
در عمل، تاکنون هرگز با این مشکل در یک کلاس سرویس مبتنی بر DI مواجه نشده‌ام.
احتمال اینکه در میانه اجرای یک متد، به‌اشتباه Logger یا Repository را Reassign کنید بسیار کم است.
اما در Entityها و Value Objectها که Immutability اهمیت بیشتری دارد، این موضوع می‌تواند دردسرساز شود.
به همین دلیل هنوز در این بخش با احتیاط بیشتری عمل می‌کنم.
❌ چه زمانی هنوز از Constructorهای سنتی استفاده می‌کنم؟

با وجود تمام مزایا، هنوز همه چیز را به Primary Constructor تبدیل نکرده‌ام.
برخی سناریوها همچنان برای Constructorهای کلاسیک مناسب‌تر هستند.
1️⃣ اعتبارسنجی پیچیده

اگر لازم باشد قبل از مقداردهی، پارامترها اعتبارسنجی شوند، به بدنه Constructor نیاز خواهید داشت.
public class EmailAddress
{
private readonly string _value;

public EmailAddress(string value)
{
if (string.IsNullOrWhiteSpace(value) || !value.Contains('@'))
{
throw new ArgumentException(
"Invalid email address.", nameof(value));
}

_value = value;
}
}
More from @csharpgeeks
  1. Sep 22, 2026یه مدتی قراره از دنیای NET. فاصله بگیرم، چون وقتشه برم سربازی. راستش نمیدونم این مدت رو چج…
  2. Sep 20, 2026🔥 حالا مشکل اصلی: Alert Storm فرض کن Database از دسترس خارج شده. ۱۰۰ Pod داری. هر Pod می‌…
  3. Sep 20, 2026🚨 طراحی سیستم Monitoring و Alerting در یک سیستم بزرگ فرض کن ساعت ۳ صبح است. سیستم شما با…
  4. Sep 19, 2026#Engineering_Leadership تصمیم نگرفتن هم یک تصمیم است یه چیز عجیب توی تیم‌های مهندسی: گاهی…
  5. Sep 19, 2026☑ چک‌لیست آماده‌سازی تیم، فرایندها و زیرساخت برای توسعه با AI توجه: هیچ چک‌لیستی جهان‌شمول…
  6. Sep 19, 2026📌پایان یک انتظار طولانی: اعتبارسنجی ناهمگام (Async Validation) در NET 11.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →