عنوان:

‫StringValues: ابزاری فراتر از آرایه‌های رشته‌ای هوشمند


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۸/۰۶ ۰۹:۴۵
آدرس: www.dntips.ir
در دنیای توسعه وب و برنامه‌های مدرن .NET، مدیریت کارآمد داده‌های رشته‌ای، به‌ویژه زمانی که یک کلید ممکن است چندین مقدار داشته باشد، از اهمیت بالایی برخوردار است. ساختار StringValues از فضای نامی Microsoft.Extensions.Primitives دقیقاً برای حل این چالش طراحی شده است. این ساختار سبک، بهینه و انعطاف‌پذیر، به توسعه‌دهندگان اجازه می‌دهد تا بدون نگرانی از تخصیص حافظه غیرضروری یا پیچیدگی‌های مدیریت آرایه، با یک یا چند رشته به صورت یکپارچه کار کنند.

مسئله: مدیریت چندین مقدار برای یک کلید
فرض کنید در یک برنامه وب، یک پارامتر کوئری مانند ?tag=csharp&tag=dotnet&tag=performance دریافت می‌کنید. یا در سرآیندهای HTTP، هدر Accept ممکن است چندین نوع MIME را شامل شود:
Accept: text/html, application/xhtml+xml, application/xml
در این موارد، یک کلید (مثل tag یا Accept) می‌تواند چندین مقدار داشته باشد. سؤال این است: چگونه این داده‌ها را به شکلی کارآمد، امن و خوانا در کد مدیریت کنیم؟

راه‌حل قدیمی: استفاده از آرایه یا لیست
قبل از معرفی StringValues، توسعه‌دهندگان معمولاً از ساختارهای عمومی مانند string[] یا List استفاده می‌کردند:
// راه‌حل قدیمی
string[] tags = context.Request.Query["tag"].ToArray();
مشکلات این روش:
  • تخصیص حافظه غیرضروری: حتی اگر فقط یک مقدار وجود داشته باشد، یک آرایه ایجاد می‌شود.
  • عدم یکپارچگی نوع: گاهی باید بررسی کنید که آیا مقدار null است، خالی است یا تک‌عنصری.
  • پیچیدگی در تبدیل: تبدیل بین string و string[] نیاز به کد اضافی داشت.
  • عملکرد ضعیف در سناریوهای پرترافیک: تخصیص‌های مکرر حافظه باعث فشار بر جمع‌آوری زباله (Garbage Collector) می‌شود.

راه‌حل جدید: ساختارStringValues
StringValues یک ساختار ارزشی/مقداری (value type) است که به صورت هوشمندانه یک یا چند رشته را نگهداری می‌کند. این ساختار در کتابخانه‌های ASP.NET Core به‌طور گسترده استفاده می‌شود؛ به‌ویژه در IQueryCollection، IHeaderDictionary و IFormCollection.

ویژگی‌های کلیدیStringValues
ویژگیتوضیح
تک یا چندمقداریمی‌تواند یک string یا یک string[] را نمایندگی کند
تبدیل ضمنیبه string یا string[] به صورت خودکار تبدیل می‌شود
اندیس‌گذاری و تکرارپذیریمثل آرایه عمل می‌کند: values[0]، foreach
عملکرد بالاتخصیص حافظه بسیار کم؛ حتی در حالت تک‌عنصری
پشتیبانی از کلید دیکشنریمی‌تواند به عنوان کلید در Dictionary استفاده شود

استفاده عملی
1. مقدار تکی
using Microsoft.Extensions.Primitives;

StringValues greeting = "سلام، دنیا!";

// دسترسی مستقیم
Console.WriteLine(greeting);        // خروجی: سلام، دنیا!
Console.WriteLine(greeting[0]);     // خروجی: سلام، دنیا!
نکته: حتی با یک مقدار، نیازی به ایجاد آرایه نیست.

2. چندین مقدار
StringValues tags = new StringValues(new[] { "csharp", "dotnet", "performance" });

// دسترسی با اندیس
Console.WriteLine(tags[1]); // خروجی: dotnet

// تکرار با foreach
foreach (var tag in tags)
{
    Console.WriteLine(tag);
}

3. تبدیل ضمنی به آرایه
StringValues fruits = new StringValues(new[] { "سیب", "موز", "گیلاس" });

string[] array = fruits; // تبدیل ضمنی!

foreach (var fruit in array)
{
    Console.WriteLine(fruit);
}

4. بررسی خالی بودن
StringValues empty = StringValues.Empty;

if (StringValues.IsNullOrEmpty(empty))
{
    Console.WriteLine("هیچ مقداری وجود ندارد");
}
نکته:StringValues.Empty یک نمونه ایستا و بهینه‌شده است که معادل default(StringValues) است و نیازی به new ندارد.

کاربردهای پیشرفته

استفاده به عنوان کلید دیکشنری
var cache = new Dictionary<StringValues, string>();

StringValues key = new StringValues(new[] { "user", "123" });
cache[key] = "داده‌های کش‌شده";

Console.WriteLine(cache[key]);
این قابلیت در سناریوهای کلید ترکیبی (مثل ترکیب کاربر + نقش) بسیار مفید است.

ترکیب با ASP.NET Core
[HttpGet]
public IActionResult Search([FromQuery] string[] tag)
{
    StringValues tags = Request.Query["tag"]; // خودکار StringValues است
    return Ok(tags);
}
در اینجا، Request.Query["tag"] از نوع StringValues است؛ حتی اگر فقط یک مقدار ارسال شود.

نکات عملکردی (Performance Tips)
  • از StringValues.Empty به جای new StringValues() استفاده کنید.
  • از تبدیل ضمنی به string[] فقط در صورت نیاز استفاده کنید؛ در اکثر موارد، مستقیماً با StringValues کار کنید.
  • در حلقه‌های پرترافیک، از Count و اندیس‌گذاری استفاده کنید تا از تخصیص‌های IEnumerator جلوگیری شود.
for (int i = 0; i < values.Count; i++)
{
    Console.WriteLine(values[i]);
}

نتیجه‌گیری
StringValues چیزی فراتر از یک “آرایه رشته‌ای هوشمند” است؛ این یک ابزار بهینه‌سازی‌شده برای دنیای واقعی وب است. با پشتیبانی از تبدیل ضمنی، اندیس‌گذاری، تکرارپذیری و عملکرد بالا، این ساختار به شما اجازه می‌دهد کد تمیزتر، سریع‌تر و کم‌مصرف‌تر بنویسید.
چه در حال پردازش کوئری استرینگ باشید، چه سرآیندهای HTTP یا داده‌های فرم، StringValues بهترین دوست شماست. از امروز، به جای string[] یا List رشته‌ای، در سناریوهای وب از StringValues استفاده کنید؛ تفاوت را در عملکرد و خوانایی کد حس خواهید کرد.

خلاصه نکات کلیدی:
  • یک یا چند مقدار را با یک نوع مدیریت کنید
  • بدون تخصیص آرایه در حالت تک‌عنصری
  • تبدیل ضمنی به string و string[]
  • قابل استفاده به عنوان کلید دیکشنری
  • بهینه‌شده برای ASP.NET Core

با StringValues، مدیریت رشته‌های چندمقداری دیگر یک چالش نیست؛ بلکه یک فرصت برای نوشتن کدی حرفه‌ای‌تر است.