تحلیل و بررسی قابلیت Partial Numeric Parsing در NET 11.
نویسنده: وحید نصیری
تاریخ: ۱۴۰۵/۰۵/۲۲ ۱۰:۱۵
آدرس: www.dntips.ir
چکیده: در نسخههای پیشین .NET، پردازش و پارس کردن رشتههای حاوی اعداد در قالبهایی مانند CSV، JSON یا فرمتهای سفارشی، مستلزم جداسازی پیشفرض (Splitting)، کپیسازی حافظه (Allocation) یا انجام فرآیندهای پیچیده پردازش رشته بود. هرگونه کاراکتر اضافی در انتهای بخش عددی به عنوان خطای پارس (Parse Failure) تلقی میشد. در .NET 11 Preview 7، مایکروسافت با معرفی متد جدیدTryParsePartialدر اینترفیسINumberBase، امکان پارس جزیی یا تدریجی (Partial Parsing) اعداد را فراهم کرده است. این قابلیت به توسعهدهنده اجازه میدهد بدون نیاز به کپیسازی داده یا برش پیشفرض متون، مقدار عددی اولیه را استخراج کرده و از تعداد کاراکترهای مصرفشده (charsConsumed) برای ادامه پردازش مابقی ورودی استفاده کند. در این مقاله، نیازمندیها، ساختار فنی، نحوه پیادهسازی و جزئیات معماری داخلی این ویژگی مورد بررسی قرار میگیرد.
ReadOnlySpan و ReadOnlySequence داشته است. با این حال، یکی از چالشهای همیشگی در پردازش فرمتهای متنی ساختاریافته (نظیر فایلهای CSV، گزارشهای متنی یا پروتکلهای شبکه)، استخراج مقادیر عددی از میان متون متصل به هم بوده است. پیش از .NET 11، متدهای TryParse انتظار داشتند که تمام ورودی دادهشده منطبق با فرمت عددی درخواستی باشد. وجود هرگونه کاراکتر جداکننده (Delimiter) مانند کاما یا نقطه-کاما در انتهای عدد، منجر به شکست عملیات پارس میشد. توسعهدهندگان مجبور بودند ابتدا جداکننده را پیدا کرده، بخش عددی را برش بزنند (Slice) و سپس آن را پارس کنند. ویژگی Partial Numeric Parsing با افزودن اورلودهای جدید TryParsePartial به اینترفیس INumberBase، این فرآیند را بهطور بنیادین ساده و بهینهسازی کرده است.TryParsePartialTryParsePartial به توسعهدهنده امکان میدهد یک عدد را از ابتدای ورودی پارس کند و در پارامتر خروجی charsConsumed دقیقاً تعداد کاراکترها یا بایتهای خواندهشده را دریافت کند. این متد برای سه قالب ورودی اصلی پشتیبانی میشود:stringReadOnlySpanReadOnlySpan (برای متون UTF-8);) نشان میدهد:using System;
using System.Globalization;
// ورودی حاوی یک عدد و ادامه متن است
ReadOnlySpan<char> input = "123; 456";
// استفاده از متد جدید TryParsePartial
if (int.TryParsePartial(
input,
NumberStyles.Integer,
CultureInfo.InvariantCulture,
out int value,
out int charsConsumed))
{
Console.WriteLine($"مقدار پارس شده: {value}"); // خروجی: 123
// پیش بردن نماگر حافظه به اندازه کاراکترهای مصرفشده
input = input[charsConsumed..];
Console.WriteLine($"مابقی ورودی: {input}"); // خروجی: ; 456
}IndexOf) پیش از فراخوانی پارسر.INumberBase، تمامی انواع عددی استاندارد داتنت (از جمله int, double, decimal, BigInteger و...) به طور یکسان از آن پشتیبانی میکنند.INumberBaseو روش پیادهسازیTryParsePartial به عنوان Default Interface Methods (DIM) در static virtual به اینترفیس INumberBase اضافه شدهاند.TryParse متوسل میشود و در صورت موفقیت، کل طول ورودی را به عنوان charsConsumed گزارش میکند.AllowTrailingInvalidCharactersNumberStyles.AllowTrailingInvalidCharacters در نظر گرفته شده بود. اما در طراحی نهایی تصمیم بر آن شد که این پرچم از دسترسی عمومی خارج شده و با یک سنتینل داخلی (Internal Sentinel) به نام Number.AllowTrailingInvalidCharacters جایگزین شود.TryParsePartial پس از اعتبارسنجی NumberStyles ورودی کاربر، این سنتینل را که از بالاترین بیت حافظه (0x8000_0000) استفاده میکند، با استایل کاربر ترکیب (OR) میکند. این کار مانع از آن میشود که کاربر بتواند به صورت مستقیم یا غیرمجاز پرچم را از طریق متدهای عادی ارسال کند.BigInteger و Complex به دلیل داشتن روتینهای پارس مشترک و متفاوت از CoreLib، بهگونهای بهروزرسانی شدهاند که سنتینل فوق را پیش از اعتبارسنجی نهایی جدا کرده و پردازش کنند.INumberBase پیادهسازی شده است. اینترفیسهای کلیتر پارس متن یعنی IParsable، ISpanParsable و IUtf8SpanParsable برای این نسخه خارج از scope قرار گرفتهاند و ممکن است در نسخههای بعدی .NET ارتقا یابند.System.IO.Pipelines کار میکنند، معمولاً با دادههای بافرشده در قالب ReadOnlySequence یا ReadOnlySpan سرکار دارند. تا پیش از این، برای خواندن یک عدد از بایتهای ورودی شبکه، مجبور بودید مطمئن شوید که تمام بایتهای عددی در بافر موجودند و کاراکتر انتهایی آن حتماً پردازش شده است. با TryParsePartial روی ReadOnlySpan، پردازش پروتکلهای متنی متداول مانند RESP (پروتکل Redis) یا HTTP Headerها بسیار سادهتر و سریعتر میشود؛ چرا که میتوانید طول exact مقدار عددی را در لحظه دریافت کرده و بلافاصله Offset بافر خواندن را بهروزرسانی کنید.TryParsePartial در .NET 11 Preview 7 گام مهمی در جهت تکمیل ابزارهای Generic Math و بهبود کارایی پردازش متون در داتنت است. این قابلیت با رفع نیاز به کپیسازی حافظه و جداسازیهای دستی، امکان نگارش پارسرهای سریعتر، امنتر و خواناتر را برای توسعهدهندگان فراهم میسازد. پایداری اجرای تستها (عبور موفق بیش از ۷۶ هزار تست واحد در مخزن runtime) نشان از دقت و آمادگی بالای این تغییر معماری در هسته داتنت دارد.