مدیریت استراتژیهای نامگذاری در System.Text.Json و قابلیت جدید PascalCase در NET 11.
نویسنده: وحید نصیری
تاریخ: ۱۴۰۵/۰۴/۰۷ ۰۸:۱۰
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
camelCase استقبال میکند، در حالی که زبانهایی مانند پایتون به استراتژی snake_case تمایل دارند و در اکوسیستم داتنت و زبان سیشارپ، فرمت استاندارد و بومی اعضای کلاسها به صورت PascalCase تعریف میشود.System.Text.Json از زمان معرفی در نسخههای گذشته داتنت، امکان مدیریت این سیاستها را فراهم کرده است. در نسخه پیشنمایش NET 11.، مایکروسافت با افزودن یک قابلیت رسمی و پرتقاضا تحت عنوان JsonNamingPolicy.PascalCase، پازل استراتژیهای نامگذاری بومی را تکمیل کرده است. در این مقاله به بررسی عمیق این ویژگی، دلایل اهمیت آن و نحوه استفاده از آن میپردازیم.JsonNamingPolicy اضافه کرده بود تا نیاز توسعهدهندگان را بدون وابستگی به کتابخانههای شخص ثالث (مانند Json.NET) برطرف کند. این استراتژیها شامل موارد زیر بودند:CamelCase: تبدیل کلمات به صورت اولین کلمه کوچک و بقیه بزرگ (مانند firstName).KebabCaseLower و KebabCaseUpper: جداسازی کلمات با خط تیره (مانند first-name یا FIRST-NAME).SnakeCaseLower و SnakeCaseUpper: جداسازی کلمات با خط زیرین (مانند first_name یا FIRST_NAME).public sealed class Person
{
public required string FirstName { get; set; }
public required string Surname { get; set; }
}PascalCase نیز به این مجموعه اضافه شدهاست که به ما اجازه میدهد دقیقاً مطابق با قراردادهای سیستمهای مصرفکننده عمل کنیم:var person = new Person { FirstName = "James", Surname = "Bond" };
// Camel Case
Console.WriteLine(JsonSerializer.Serialize(person, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true }));
// Kebab Case (Lower & Upper)
Console.WriteLine(JsonSerializer.Serialize(person, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower, WriteIndented = true }));
Console.WriteLine(JsonSerializer.Serialize(person, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.KebabCaseUpper, WriteIndented = true }));
// Snake Case (Lower & Upper)
Console.WriteLine(JsonSerializer.Serialize(person, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, WriteIndented = true }));
Console.WriteLine(JsonSerializer.Serialize(person, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseUpper, WriteIndented = true }));
// Pascal Case (.NET 11 New Feature)
Console.WriteLine(JsonSerializer.Serialize(person, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.PascalCase, WriteIndented = true }));// Camel Case Output
{
"firstName": "James",
"surname": "Bond"
}
// Kebab Case Lower & Upper Outputs
{
"first-name": "James",
"surname": "Bond"
}
{
"FIRST-NAME": "James",
"SURNAME": "Bond"
}
// Snake Case Lower & Upper Outputs
{
"first_name": "James",
"surname": "Bond"
}
{
"FIRST_NAME": "James",
"SURNAME": "Bond"
}
// Pascal Case Output (.NET 11)
{
"FirstName": "James",
"Surname": "Bond"
}System.Text.Json به این صورت است که نام ویژگیها را دستنخورده نگه میدارد (و در نتیجه خروجی همان PascalCase کدهای سیشارپ میشود)، پس چرا مایکروسافت یک گزینه صریح به نام JsonNamingPolicy.PascalCase را اضافه کرده است؟camelCase قرار میدهد. اگر در پروژهای نیاز داشته باشید که کل خروجیهای یک وبAPI یا یک کلاینت خاص به صورت PascalCase ارسال شود، در گذشته مجبور بودید مقدار PropertyNamingPolicy را برابر null قرار دهید که رویکرد چندان خوانایی نبود. وجود یک کلاس صریح، وضوح و خلوص کد (Clean Code) را افزایش میدهد.JsonSerializerOptions) یا نمونهای از JsonNamingPolicy به عنوان یک شیء تزریق وابستگی (DI) یا پارامتر بین متدها و کتابخانههای مختلف پاس داده میشود، داشتن یک تمایز صریح برای فرمت پاسکال به شما اجازه میدهد تا بدون نیاز به شرطهای پیچیده بر روی مقادیر null، سیاست نامگذاری را کنترل و بازنویسی کنید.JsonNamingPolicy.PascalCase در پیشنمایش NET 11.، گامی مهم در جهت هماهنگی هرچه بیشتر، افزایش خوانایی کد و ارائه پلتفرمی منسجم است. با استفاده از این قابلیت، توسعهدهندگان داتنت اکنون ابزاری کامل و بدون نقص برای مدیریت هر نوع قرارداد نامگذاری در تعامل با دنیای بیرون از اکوسیستم خود در اختیار دارند. پیشنهاد میشود در زمان ارتقا به نسخههای جدید، از این سیاست صریح برای بهبود شفافیت در لایههای سریالایزیشن برنامههای خود استفاده کنید.JsonNamingPolicyAttributeدر سناریوهای پیچیدهPropertyNamingPolicy در لایه JsonSerializerOptions اعمال میشد؛ این یعنی سیاست انتخاب شده (مانند CamelCase یا SnakeCase) به صورت یکپارچه و سراسری (Global) بر روی تمام ویژگیهای (Properties) یک شیء یا کل پروژه تأثیر میگذاشت.snake_case و ویژگی دیگر در همان شیء به صورت camelCase تعریف شده است.JsonConverter سفارشی و پیچیده بودند که نیازمند مدیریت دستی کل فرآیند خواندن و نوشتن توکنهای JSON بود.[JsonNamingPolicy][JsonNamingPolicy] و انام (Enum) جدید JsonKnownNamingPolicy انجام میشود.using System.Text.Json.Serialization;
public sealed class Spy
{
// اعمال سیاست حروف کوچک همراه با خط زیرین
[JsonNamingPolicy(JsonKnownNamingPolicy.SnakeCaseLower)]
public required string FirstName { get; init; }
// اعمال سیاست کوهانشتری
[JsonNamingPolicy(JsonKnownNamingPolicy.CamelCase)]
public required string Surname { get; init; }
// اعمال سیاست کوهانشتری
[JsonNamingPolicy(JsonKnownNamingPolicy.CamelCase)]
public required DateOnly DateOfBirth { get; init; }
}JsonSerializerOptions نیست. موتور System.Text.Json به طور خودکار اتریبیوتهای ثبتشده روی ویژگیها را کشف کرده و اعمال میکند:using System.Text.Json;
var spy = new Spy
{
FirstName = "James",
Surname = "Bond",
DateOfBirth = new DateOnly(1950, 1, 1)
};
var options = new JsonSerializerOptions
{
WriteIndented = true // فقط برای فرمتدهی خوانای خروجی
};
Console.WriteLine(JsonSerializer.Serialize(spy, options));{
"first_name": "James",
"surname": "Bond",
"dateOfBirth": "1950-01-01"
}FirstName به صورت تکعضوی از سیاست snake_case پیروی کرده، در حالی که سایر ویژگیها فرمت camelCase را به خود گرفتهاند.JsonSerializerOptions یک سیاست سراسری مثل PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower تعریف کرده باشید، اما روی یک ویژگی خاص اتریبیوت [JsonNamingPolicy] را قرار دهید، تنظیماتِ نقطهایِ اتریبیوت اولویت بالاتر داشته و تنظیمات سراسری را برای آن ویژگی خاص نادیده میگیرد (Override میکند).[JsonPropertyName]: شاید بپرسید این اتریبیوت چه تفاوتی با [JsonPropertyName("custom_name")] دارد؟ اتریبیوت قدیمیِ JsonPropertyName نام ویژگی را به صورت یک رشته ثابت (Hardcoded String) تغییر میدهد. اما [JsonNamingPolicy] یک قانون یا استراتژی را به ویژگی تزریق میکند. این رویکرد به ویژه زمانی مفید است که نام ویژگیها در کدهای شما به دلایلی تغییر کند؛ در این حالت، سیاست نامگذاری همچنان به درستی روی نام جدید اعمال میشود و نیازی به تغییر رشتههای هاردکد شده نیست.[JsonNamingPolicy] در .NET 11، کنترل دانه-ریز (Fine-grained) و بسیار منعطفی را بدون نیاز به نوشتن بویلرپلیتکدها (Boilerplate code) یا کانورترهای سفارشی در اختیار توسعهدهنده قرار میدهد. این قابلیت، توسعه نرمافزارهای داتنتی را در مواجهه با سیستمهای میراثی (Legacy) یا APIهای شخص ثالث با طراحی غیراستاندارد، بیش از پیش لذتبخش و سادهتر میکند.