| کانال توسعهدهندگان سیشارپ |
رفتن به کانال در Telegram
⭕️ کانال توسعهدهندگان سیشارپ دولوپیکس 💠 دولوپیکس | جامعه توسعهدهندگان ایرانی 💎 @Developix 🚀 Developix.ir 📌 پشتیبانی و تبلیغات: @DevelopixSupport
نمایش بیشتر1 008
مشترکین
اطلاعاتی وجود ندارد24 ساعت
+27 روز
-330 روز
آرشیو پست ها
در کد زیر تلاش شده یک Singleton ساده پیادهسازی شود، اما هم از نظر Thread-Safety و هم از نظر الگوی طراحی، چند مشکل جدی دارد و در سناریوهای Multi-Thread ممکن است چند نمونه از کلاس ساخته شود.
چه چیزی باید در این پیادهسازی اصلاح شود تا الگوی Singleton بهصورت ایمن و صحیح در سیشارپ پیادهسازی شود؟
🔖 #CSharp #سی_شارپ
👤 Developix
💎 Channel: @DevelopixCSharp
🕒 NodaTime؛ خداحافظ DateTime گیجکننده
کار با
DateTime و TimeZone در .NET مخصوصاً در پروژههای چندمنطقهای واقعاً دردسرسازه؛ از UTC و Local گرفته تا DST و Offsetهای مختلف.
اینجا NodaTime وارد میشه؛ یک کتابخانه قدرتمند برای مدیریت زمان و تاریخ که مدلش خیلی شفافتر از DateTime پیشفرضه و توی پروژههای مالی، رزرو، لاگینگ و سرویسهای بینالمللی عالی جواب میده. 🚀
چرا NodaTime؟
• تایپهای واضح مثل Instant، LocalDate، LocalDateTime، ZonedDateTime
• پشتیبانی دقیق از IANA Time Zone
• جلوگیری از باگهای زمانبندی، مخصوصاً اطراف تغییر ساعت (DST)
• API تمیز و قابل تست؛ مخصوصاً برای Domain-Driven Design
نصب با NuGet:
dotnet add package NodaTimeنمونه استفاده ساده:
using NodaTime; var now = SystemClock.Instance.GetCurrentInstant(); var tz = DateTimeZoneProviders.Tzdb["Europe/Berlin"]; var zoned = now.InZone(tz); LocalDate invoiceDate = new(2026, 1, 26); LocalDate dueDate = invoiceDate.PlusDays(14);برای هر سرویسی که زمان و زمانبندی توش مهمه، همراه کردنش با NodaTime جلوی کلی Memory Bug و رفتار عجیب رو میگیره. پیشنهاد میشه حتماً تو پروژه بعدی امتحان بشه و کمکم
DateTime خام رو کنار بذاری. 💡
مستندات رسمی:
Website & Docs
GitHub
🔖 #CSharp #سی_شارپ #CSharp #NodaTime #_NET #Time #DateTime #Backend
👤 Developix
💎 Channel: @DevelopixCSharp+1
❓ در نمونه کد بالا در نسخهٔ اول برای محاسبهٔ میانگین یک کالکشن از اعداد، تمام دادهها دو بار پیمایش و چندین بار boxing/unboxing انجام میشود که هم روی کارایی و هم روی مصرف مموری در سناریوهای پردازش حجم بالای داده تأثیر منفی دارد. با استفاده از Generic و Delegate مناسب (مثل
Func<T, double>) میتوان منطق را طوری پیادهسازی کرد که هم type-safe باشد و هم فقط یک بار روی دادهها پیمایش شود. کدام نسخه از این پیادهسازی در سناریوهای real-world (مثلاً پردازش لاگ، دادههای سنسور یا تراکنشها) مناسبتر است و چرا استفاده از object و is چکهای پیاپی میتواند به یک Anti Pattern در طراحی APIهای عمومی تبدیل شود؟
🔖 #CSharp #سی_شارپ
👤 Developix
💎 Channel: @DevelopixCSharpخیلی از Memory Leakهای ریز تو پروژههای #CSharp از یه چیز ساده شروع میشن: فراموشکردن Dispose روی resourceهایی مثل
HttpClient، SqlConnection، فایلها و… 😅
تو داتنت جدید، using راحتتر و خواناتر شده و اگر درست استفاده بشه، هم کد تمیزتر میشه هم از نشت حافظه و handleها جلوگیری میکنه. 👇
۱️⃣ الگوی قدیمی using بلاکی
using (var stream = File.OpenRead("data.json"))
using (var reader = new StreamReader(stream))
{
var content = reader.ReadToEnd();
Console.WriteLine(content);
}
اینجا بهمحض خروج از بلاک، هر دو object بهصورت خودکار Dispose میشن.
۲️⃣ الگوی جدید using declaration (از C# 8 به بعد)
برای کاهش nesting و خوانایی بیشتر:
using var stream = File.OpenRead("data.json");
using var reader = new StreamReader(stream);
var content = reader.ReadToEnd();
Console.WriteLine(content);
// در انتهای متد، خودشون Dispose میشن
تو این حالت، scopeِ using var کل متده؛ یعنی پایان متد = زمان Dispose. این الگو توی متدهای کوتاه و تمیز عالی جواب میده و از بلاکهای تو در تو کم میکنه. 💡
۳️⃣ نکته مهم در متدهای طولانی
اگر متد خیلی طولانیه و resource فقط تو یه بخش کوچیک لازم میشه، بهتره همون الگوی بلاکی رو نگه داری تا resource زودتر آزاد بشه و تا آخر متد تو حافظه نمونه.
۴️⃣ async و IAsyncDisposable
برای کلاسهایی که IAsyncDisposable رو پیادهسازی میکنن (مثلاً بعضی clientهای شبکه):
await using var client = new SomeAsyncClient();
await client.DoWorkAsync();
اینجا در انتهای scope، بهجای Dispose، متد DisposeAsync صدا زده میشه و resourceها بهشکل async آزاد میشن.
جمعبندی: استفاده درست از using (بهخصوص using var و await using) یه راه خیلی ساده و کاربردی برای جلوگیری از Memory Leak و تمیز نگهداشتن کده. چند جای پروژه رو که resource سنگین دارن چک و این الگو رو اعمال کن؛ تأثیرش تو performance و پایداری سرویس کاملاً قابل لمسه. 🚀
🔗 مرجع رسمی Microsoft Docs:
https://learn.microsoft.com/dotnet/csharp/language-reference/statements/using
🔖 #CSharp #سی_شارپ #C# #using #dispose #memory #performance #_NET
👤 Developix
💎 Channel: @DevelopixCSharpاین کد C# را در نظر بگیرید:
public class UserService
{
private static HttpClient _client = new HttpClient();
public async Task<string> GetUserNameAsync(int id)
{
_client.BaseAddress = new Uri("https://api.example.com/");
_client.DefaultRequestHeaders.Clear();
_client.DefaultRequestHeaders.Add("X-Request-Id", Guid.NewGuid().ToString());
var response = await _client.GetAsync($"users/{id}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
در این پیادهسازی از static HttpClient استفاده شده، اما همچنان یک Memory Leak / Thread-Safety Anti Pattern جدی در نحوه تنظیم BaseAddress و DefaultRequestHeaders وجود دارد که در سناریوهای چند-ترد یا چند-ریکوئست میتواند مشکلساز شود.
چه چیزی باید در این کلاس اصلاح شود تا استفاده از HttpClient هم ایمنتر و هم بدون این Anti Pattern باشد؟
🔖 #CSharp #سی_شارپ
👤 Developix
💎 Channel: @DevelopixCSharp⚡ استفاده حرفهای از ConfigureAwait(false) در async/await
خیلی وقتها توی کتابخونهها و لایههای غیر UI، از async/await استفاده میشه ولی ناخواسته Performance و Scale خراب میشه؛ فقط به خاطر برنگشتنِ درست به Thread قدیمی.
نکتهٔ مهم اینه: در کدهای غیر UI (مثل لایهٔ Data Access، Service، Library) معمولاً نیازی نیست بعد از
await برگردیم به همون SynchronizationContext قبلی. اینجاست که 🧠 ConfigureAwait(false) کمک میکنه.
✅ ایده:
هرجا در Library Code هستیم و بعد از await به Context قبلی نیاز نداریم، از ConfigureAwait(false) استفاده کنیم تا:
- Deadlockهای کلاسیک در ASP.NET قدیمی کمتر بشه
- Performance بهتر بشه چون نیاز به Capture/Restore Context نیست
مثال ساده در یک Service غیر UI:
public async Task<UserDto> GetUserAsync(int id)
{
// فرض: این متد توی لایه Service یا Repository صدا زده میشه
using var client = new HttpClient();
var response = await client
.GetAsync($"https://api.example.com/users/{id}")
.ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var json = await response.Content
.ReadAsStringAsync()
.ConfigureAwait(false);
return JsonSerializer.Deserialize<UserDto>(json)!;
}
📌 نکات مهم:
- توی UI (WPF, WinForms, MAUI) یا Razor Pages که بعد از await میخوای کنترلهای UI رو آپدیت کنی، از ConfigureAwait(false) استفاده نکن چون به Thread UI برنمیگردی.
- در ASP.NET Core بهخاطر نداشتن SynchronizationContext کلاسیک، مشکل Deadlock خیلی کمتره؛ ولی هنوز هم برای Libraryهای عمومی، استفاده از ConfigureAwait(false) یک Practice خوب حساب میشه.
- سعی کن این الگو رو توی کل لایههای Library یکدست نگه داری تا رفتار کد قابلپیشبینی بمونه.
برای توضیح رسمی مایکروسافت دربارهٔ async/await و Context:
مستندات async در C# (Microsoft Docs)
امتحان این روش توی Serviceها و Libraryها، مخصوصاً زیر لود بالا، خیلی زود توی لاگها و Performance خودش رو نشون میده 🚀
🔖 #CSharp #سی_شارپ #CSharp #async #ConfigureAwait #Performance #_NET
👤 Developix
💎 Channel: @DevelopixCSharp+1
در نمونهکد بالا متد GetUsersByRoleAsync در نسخهٔ اول بهخاطر فچکردن همه رکوردها در حافظه و بعد فیلتر کردن با
Where روی List<T>، هم Memory مصرفی را بالا میبرد و هم روی دیتابیسهای بزرگ باعث افت شدید Performance میشود. در مقابل، در نسخهٔ دوم با نگه داشتن Query به صورت IQueryable<User> و استفاده از Where قبل از ToListAsync، فیلتر روی خود دیتابیس انجام میشود و فقط دادهٔ موردنیاز لود میشود. در سناریوهایی که جدولهای بزرگ دارید یا روی Cloud Database کار میکنید، این الگو باعث کاهش چشمگیر حجم دادهٔ منتقلشده و بهبود زمان پاسخ متدهای Repository خواهد شد. همچنین با برگرداندن IReadOnlyList<User> به جای List<User>، به Contract بهتری از نظر Encapsulation و جلوگیری از Mutation ناخواسته میرسید.
🔖 #CSharp #سی_شارپ
👤 Developix
💎 Channel: @DevelopixCSharpDependency Injection تمیز در ASP.NET Core برای تستپذیری بهتر ⚙️
یکی از مهمترین قدمها برای Clean Code در پروژههای ASP.NET Core این است که وابستگیها را مستقیم new نکنیم، بلکه از Dependency Injection استفاده کنیم. این کار هم کد را تمیزتر میکند، هم تستپذیری و امکان تغییر پیادهسازیها را بالا میبرد. 💡
فرض کنید در یک Web API کنترلری دارید که مستقیم وابسته به Service است:
public class OrdersController : ControllerBase
{
private readonly OrderService _orderService;
public OrdersController()
{
_orderService = new OrderService();
}
[HttpGet("api/orders/{id}")]
public async Task<IActionResult> Get(int id)
{
var order = await _orderService.GetByIdAsync(id);
return order is null ? NotFound() : Ok(order);
}
}
این طراحی چند مشکل جدی دارد:
• کنترلر مستقیماً به OrderService Couple شده است.
• تست Unit برای کنترلر سخت است، چون نمیتوان Mock تزریق کرد.
• در آینده اگر سرویس عوض شود (مثلاً کش اضافه شود)، باید خود کنترلر را تغییر بدهید.
راه تمیزتر این است که یک Interface تعریف کنید و آن را از DI Container تزریق کنید:
public interface IOrderService
{
Task<Order?> GetByIdAsync(int id);
}
public class OrderService : IOrderService
{
private readonly AppDbContext _db;
public OrderService(AppDbContext db)
{
_db = db;
}
public Task<Order?> GetByIdAsync(int id)
=> _db.Orders.FindAsync(id).AsTask();
}
حالا کنترلر فقط Interface را میشناسد:
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
private readonly IOrderService _orderService;
public OrdersController(IOrderService orderService)
{
_orderService = orderService;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
var order = await _orderService.GetByIdAsync(id);
return order is null ? NotFound() : Ok(order);
}
}
و در Program.cs (یا Startup قدیمیها):
builder.Services.AddScoped<IOrderService, OrderService>();
مزیتها 🧩
• تستپذیری بالا: در تستها میتوان یک FakeOrderService یا Mock تزریق کرد.
• پیادهسازی قابلتعویض: بدون تغییر کنترلر میتوانید CachingOrderService اضافه کنید.
• رعایت اصل D از SOLID (Dependency Inversion): وابستگی به Abstraction نه Concrete Class.
برای مطالعه بیشتر، مستندات رسمی مایکروسافت درباره DI در ASP.NET Core خیلی شفاف و بهروز است:
Microsoft Learn - Dependency injection in ASP.NET Core
قدمبهقدم اگر وابستگیهای مستقیم را به شکل Interface + DI تبدیل کنید، معماری اپلیکیشن تمیزتر، منعطفتر و آمادهٔ رشد میشود. 🚀
🔖 #CSharp #سی_شارپ #C# #_NET #ASP_NET_Core #Dependency_Injection #SOLID #Clean_Code
👤 Developix
💎 Channel: @DevelopixCSharp🔹 یک تکه کد زیر مربوط به CSharp است که روی رفتار closure و async/await در حلقه تاکید دارد.
خروجی نهایی اجرای متد Main چیست؟
(ترتیب و مقدار دقیق خطوطی که در Console چاپ میشوند را بنویسید.)
🔖 #CSharp #سی_شارپ
👤 Developix
💎 Channel: @DevelopixCSharp
در پروژههای ASP.NET Core وقتی یک سرویس تعداد زیادی وابستگی دارد، خوانایی، تستپذیری و نگهداری کد سخت میشود. ✅
ایدهی عملی امروز: بهجای تزریق مستقیم چندین سرویس در یک کلاس، یک Facade یا Aggregate Service بسازید تا زنجیرهی وابستگی ساده، قابل تست و خواناتر شود. این رویکرد از Service Locator و constructor bloat جلوگیری میکند و مسئولیتها را بهتر جدا میکند. 🧩
مثال واقعی: کلاس OrderService که به Inventory، Payment و Notification وابسته است. اول نسخهٔ «بد» با constructor پر از وابستگیها:
<!-- escaped C# code for Telegram -->
public class OrderService
{
private readonly IInventoryService _inventory;
private readonly IPaymentService _payment;
private readonly INotificationService _notification;
public OrderService(IInventoryService inventory, IPaymentService payment, INotificationService notification)
{
_inventory = inventory;
_payment = payment;
_notification = notification;
}
public async Task<bool> PlaceOrderAsync(Order order)
{
if (!await _inventory.ReserveAsync(order)) return false;
var paid = await _payment.ChargeAsync(order);
if (!paid) { await _inventory.ReleaseAsync(order); return false; }
await _notification.SendAsync(order);
return true;
}
}
با الگوی Facade، مجموعهٔ عملیات مرتبط را در یک رابط قرار میدهیم تا OrderService ساده شود:
<!-- escaped C# code -->
public interface IOrderProcessor { Task<bool> ProcessAsync(Order order); }
public class OrderProcessor : IOrderProcessor
{
private readonly IInventoryService _inventory;
private readonly IPaymentService _payment;
private readonly INotificationService _notification;
public OrderProcessor(IInventoryService inventory, IPaymentService payment, INotificationService notification) { ... }
public async Task<bool> ProcessAsync(Order order)
{
// همان منطق ترکیبی اینجا قرار میگیرد
}
}
public class OrderService
{
private readonly IOrderProcessor _processor;
public OrderService(IOrderProcessor processor) { _processor = processor; }
public Task<bool> PlaceOrderAsync(Order order) => _processor.ProcessAsync(order);
}
نکات عملی:
• با Facade، تست واحد سادهتر میشود (فقط IOrderProcessor موک میشود). 🧪
• مسئولیتها تمیز جدا میشوند و هر سرویس کوچکتر و تکوظیفهای میماند. ✂️
• از تزریق مستقیم تعداد زیادی سرویس در کنترلرها یا سرویسهای سطح بالا خودداری کنید.
مراجع معتبر: مستندات Microsoft Dependency Injection و الگوهای طراحی در Refactoring.Guru برای جزئیات بیشتر. 📚
شروع به کوچکسازی زنجیرههای تزریق در پروژه کنونی کنید و تغییرات را با تستهای واحد همراه کنید — تاثیرش را سریع احساس خواهید کرد. 🚀
🔖 #CSharp #سی_شارپ #Facade #DependencyInjection #SOLID #C# #ASP_NET_Core
👤 Developix
💎 Channel: @DevelopixCSharpRepost from | Codilo |
🍉 یلدای امسال رو کُدیلویی بگذرونید!
🍓 تا پایان روز جمعه با دعوت دو کاربر جدید به کدیلو، فایل های کدیلو رو رایگان دریافت کنید
🥝 یلدای خوبی داشته باشید (:
💎 @Codilo
توی Minimal API ها بعضی وقتها پارامترهاتون زیاد میشه و خوانایی کدتون رو پایینتر میاره، میتونید مثل عکس بالا اونها رو توی یک رکورد تعریف کنید و با اتریبیوت
[AsParameters] از اون استفاده کنید.
👤 MHReza
💎 Channel: @DevelopixCSharpاحتمالا شده که موقع کار با Minimal API ها نیاز شده که یه سرویسی رو اینجکت کنید و ازش استفاده کنید.
با اتریبیوت
[FromServices] مانند کد بالا میتونید اون سرویس رو از DI container بگیرید و داخل کدتون استفاده کنید.
👤 MHReza
💎 Channel: @DevelopixCSharpلایو دوم مربوط به انتشار دات نت که امشب ساعت هشت هست رو میتونید از لینک زیر تماشا کنید
https://www.youtube.com/watch?v=vU-iZcxbDUk
👤 QWxp
💎 Channel: @DevelopixCSharp
دات نت 8 به طور رسمی منتشر شد
لینک دانلود:
https://dotnet.microsoft.com/en-us/download/dotnet/8.0
👤 QWxp
💎 Channel: @DevelopixCSharp
بهزودی داتنت 8 منتشر میشه 🎉 با کلی قابلیت های جدید ( که بیشترشون قرار نیست به دردمون بخوره👌).
توی چند روز آینده قراره کنفرانس های متعددی توسط مایکروسافت در این رابطه برگذار بشه.
اولیش فردا هست، میتونید توی یوتوب از این لینک تماشا کنید.
👤 QWxp
💎 Channel: @DevelopixCSharp
احتمالا شده که خواستید یه کدی رو تست کنید، ولی نمیخواید به خاطرش به پروژه ایجاد بکنید. ابزار
CSharpRepl اینجا بدردتون میخوره.
این ابزار بهتون کمک میکنه کدتون رو توی محیط کامند لاین تست کنید. برای نصبش میتونید دستور
dotnet tool install -g csharpreplرو داخل ترمینالتون وارد کنید. با وارد کردن دستور
csharprepl وارد محیط کامند لاین میشید و میتونید هر کدی رو بنویسید.
اگه بخواید پکیجی رو هم نصب کنید با این دستور میتونید اون رو نصب کنید، برای مثال دستور زیر رو ببینید:
#r "nuget: Newtonsoft.Json"با این دستور پکیج Newtonsoft.Json براتون نصب میشه برای اطلاعات بیشتر در مورد این ابزار میتونید به صفحه گیتهابش مراجعه کنید و بیشتر در موردش مطالعه کنید. 👤 MHReza 💎 Channel: @DevelopixCSharp
توصیه میکنم این پلیلیست رو در یوتیوب حتماً دنبال کنید.
مطالب خوبی در مورد EF Core منتشر میکنه.
🔗 لینک
👤 MHReza
💎 Channel: @DevelopixCSharp
معرفی کتابخانه RazorSlices
این کتابخانه یک
template سبک و سریع برای asp.net core minimal api ساخته شده، بدون نیاز به استفاده از MVC، بهینه شده برای رندر کردن HTML در Razor یا Blazor.
برای شروع:
1.کتابخانه را نصب کنید
$ dotnet add package RazorSlices
2.یک دایرکتوری به نام Slices توی پروژتون ایجاد کنید، و داخل اون یک فایل به نام ViewImports.cshtml_ با این محتوا ایجاد کنید:
@inherits RazorSliceHttpResult
@using System.Globalization;
@using Microsoft.AspNetCore.Razor;
@using Microsoft.AspNetCore.Http.HttpResults;
@tagHelperPrefix disable_tagHelpers:
@removeTagHelper *, Microsoft.AspNetCore.Mvc.Razor
3. یک cshtml.* دیگه داخل دایرکتوری Slices ایجاد کنید :
@inherits RazorSliceHttpResult<DateTime>
<p>
Hello from Razor Slices! The time is @Model
</p>
4.حالا به راحتی داخل minimal api اتون صفحات HTML رو رندر کنید:
app.MapGet("/hello", () => Results.Extensions.RazorSlice("/Slices/Hello.cshtml", DateTime.Now));
🧷درحال حاضر موارد زیر در این کتابخانه پشتیبانی نمیشند:
1.پشتیبانی از AOT
2.پشتیبانی از Hot Reload
3.پشتیبانی از Layout ها و Section ها
#asp #razor
👤 QWxp
💎 Channel: @DevelopixCSharp🌀 معرفی switch expression 🌀
🔸 توی نسخه سیشارپ هشت این switch expression ها معرفی شدن که باعث میشه دستورات سوییچ خودمون رو خواناتر بکنیم. بریم یه مثال ببینیم از قبل و بعد از استفاده از این switch expression ها.
🔹 توی این مثال از حالت عادیمون استفاده میکنیم.
int number = 1;
string result = "";
switch (number)
{
case 1:
result = "One";
break;
case 2:
result = "Two";
break;
case 3:
default:
result = "Default case";
break;
}
🔸حالا بریم با switch expression بازنویسیش کنیم.
int number = 1;
string result = number switch
{
1 => "One",
2 => "Two",
_ => "Default case"
};
🔹 میبینید که چقد کدمون رو کوتاهتر و خواناتر کرده.
#Tips
👤 MHReza
💎 Channel: @DevelopixCSharp