JSON و C# dynamic: لماذا لا يزال هذا ألمًا (وكيفية علاجه)
\n\nهل سبق لك أن نظرت إلى استجابة JSON من API وفكرت: "يا إلهي، لماذا أنت معقد جدًا؟" خاصة إذا كان هيكل البيانات يتغير في كل مرة مثل الطقس في سانت بطرسبرغ. المثال الكلاسيكي هو الرد من خدمة خارجية حيث يمكن أن تكون الحقول إما سلاسل نصية أو مصفوفات أو حتى null. أو عندما تحتاج إلى تحليل JSON بسرعة، ولكن إنشاء فئة منفصلة له يشبه استخدام مجهر لقطع شريحة إلكترونية.
بالضبط لمثل هذه الحالات، يوجد السحر dynamic في C#. سؤال "Deserialize JSON into C# dynamic object؟" على Stack Overflow حصد آلاف المشاهدات - وهذا ليس من قبيل الصدفة. في عام 2025، عندما أصبحت الخدمات المصغرة وواجهات برمجة التطبيقات الديناميكية هي القاعدة، فإن القدرة على العمل مع JSON بسرعة ومرونة هي قوة خارقة للمطور.
في هذه المقالة، سنستعرض أفضل الممارسات لإلغاء تسلسل JSON إلى كائن dynamic في C#. بدون نظرية مملة، فقط كود وأمثلة ونصائح عملية. هيا بنا!
\n\nلماذا dynamic؟ وليس فقط JObject؟
\n\nسؤال جيد. في C#، يوجد JObject (من Newtonsoft.Json) و JsonDocument (من System.Text.Json). كلاهما يمكنه تحليل JSON "أثناء التنقل". لكن dynamic يعطي شيئًا مهمًا واحدًا - السكر النحوي.
قارن:
\n\n// عبر JObject\nvar json = JObject.Parse(rawJson);\nvar name = (string)json["user"]["name"];\n\n// عبر dynamic\ndynamic obj = JsonConvert.DeserializeObject<dynamic>(rawJson);\nvar name = obj.user.name;\n\n\nالخيار الثاني يُقرأ ككود عادي، وليس كـ "احصل على المفتاح، حوّل النوع، تحقق من null". هذا مفيد بشكل خاص عندما يكون JSON متداخلاً بعمق.
\n\nالطريقة 1: الكلاسيكية - Newtonsoft.Json (Json.NET)
\n\nنعم، نحن في عام 2025، لكن Newtonsoft.Json لا يزال حيًا وبصحة جيدة. العديد من المشاريع القديمة، وحتى بعض الحديثة، تستخدمه. لماذا؟ المرونة وقابلية التوسع وملايين الإعدادات.
\n\nمثال أساسي
\n\nusing Newtonsoft.Json;\n\nstring json = @"\n{\n 'name': 'أليكسي',\n 'age': 30,\n 'skills': ['C#', 'Python', 'SQL'],\n 'address': {\n 'city': 'موسكو',\n 'zip': 101000\n }\n}";\n\ndynamic obj = JsonConvert.DeserializeObject<dynamic>(json);\n\nConsole.WriteLine(obj.name); // أليكسي\nConsole.WriteLine(obj.age); // 30\nConsole.WriteLine(obj.skills[0]); // C#\nConsole.WriteLine(obj.address.city); // موسكو\n\n\nكل شيء بسيط وأنيق. لكن هناك فارق بسيط: عند العمل مع dynamic، تفقد IntelliSense والتحقق من الأنواع في وقت الترجمة. الخطأ في اسم الحقل سيظهر فقط في وقت التشغيل. لذلك:
- \n
- استخدم
dynamicفقط لقراءة البيانات التي لا تتحكم فيها. \n - احرص دائمًا على تغليف الاستدعاءات في try-catch. \n
- لا تفرط في الاستخدام - إذا كان هيكل JSON مستقرًا، فمن الأفضل إنشاء فئة DTO. \n
الطريقة 2: الحديثة - System.Text.Json
\n\nبدءًا من .NET Core 3.0، تروج Microsoft لـ System.Text.Json - سريع، أصلي، بدون تبعيات خارجية. في عام 2025، هذا هو المعيار للمشاريع الجديدة.
لكن هناك مشكلة: System.Text.Json لا يعرف كيفية إلغاء التسلسل إلى dynamic "خارج الصندوق". ستحتاج إلى القليل من الحيلة.
الخيار A: عبر JsonDocument و ExpandoObject
\n\nusing System.Text.Json;\nusing System.Dynamic;\n\nstring json = @"{""name"":""إيلينا"",""age"":25,""active"":true}";\n\nusing JsonDocument doc = JsonDocument.Parse(json);\ndynamic obj = ConvertToExpando(doc.RootElement);\n\nConsole.WriteLine(obj.name); // إيلينا\nConsole.WriteLine(obj.age); // 25\nConsole.WriteLine(obj.active); // True\n\nstatic ExpandoObject ConvertToExpando(JsonElement element)\n{\n var expando = new ExpandoObject();\n var dict = (IDictionary<string, object>)expando;\n\n foreach (var property in element.Enumera