C#: نظرة عامة على الميزات المتقدمة

1. التأمل

تتيح ميزة «الانعكاس» (Reflection) لأي برنامج فحص معلومات النوع الخاصة به ومعالجتها أثناء وقت التشغيل. وتُعد فئة Type جوهر ميزة الانعكاس، حيث تتيح الوصول إلى البيانات الوصفية مثل الحقول والخصائص والطرق.

(1) الحصول على معلومات النوع

CSHARP
using System;
using System.Reflection;

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public void SayHello() => Console.WriteLine("Hello!");
}

class Program
{
    static void Main()
    {
        Type type1 = typeof(Person);
        Type type2 = new Person().GetType();

        Console.WriteLine($"Type name: {type1.Name}");

        Console.WriteLine("Properties:");
        foreach (PropertyInfo p in type1.GetProperties())
            Console.WriteLine($"  {p.Name} ({p.PropertyType.Name})");

        Console.WriteLine("Methods:");
        foreach (MethodInfo m in type1.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
            Console.WriteLine($"  {m.Name}");
    }
}
TEXT 📖 للعرض فقط
Type name: Person
Properties:
  Name (String)
  Age (Int32)
Methods:
  get_Name
  set_Name
  get_Age
  set_Age
  SayHello

(2) إنشاء مثيلات ديناميكيًا

CSHARP
using System;
using System.Reflection;

class Dog
{
    public string Breed { get; set; } = "Unknown";
    public override string ToString() => $"Dog: {Breed}";
}

class Program
{
    static void Main()
    {
        Type type = typeof(Dog);
        object obj = Activator.CreateInstance(type)!;

        PropertyInfo prop = type.GetProperty("Breed")!;
        prop.SetValue(obj, "Husky");

        Console.WriteLine(obj);
    }
}
TEXT 📖 للعرض فقط
Dog: Husky

▶ مثال

CSHARP
using System;
using System.Linq;
using System.Reflection;

class Calculator
{
    public int Add(int a, int b) => a + b;
    public double Multiply(double x, double y) => x * y;
    public void Reset() { }
}

class Program
{
    static void Main()
    {
        Calculator calc = new Calculator();
        Type type = calc.GetType();

        Console.WriteLine($"Type: {type.Name}");
        Console.WriteLine($"Namespace: {type.Namespace}");
        Console.WriteLine($"Is class: {type.IsClass}");

        Console.WriteLine("Public methods:");
        MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
        foreach (MethodInfo m in methods)
        {
            string parameters = string.Join(", ", m.GetParameters().Select(p => $"{p.ParameterType.Name} {p.Name}"));
            Console.WriteLine($"  {m.ReturnType.Name} {m.Name}({parameters})");
        }
    }
}
▶ جرّب الكود
TEXT 📖 للعرض فقط
Type: Calculator
Namespace: 
Is class: True
Public methods:
  Int32 Add(Int32 a, Int32 b)
  Double Multiply(Double x, Double y)
  Void Reset()

2. السمات

السمات هي علامات إعلانية تُستخدم لإضافة بيانات وصفية إلى عناصر الكود. يمكنك استخدام السمات المدمجة أو تعريف سمات مخصصة.

(1) السمات المدمجة

CSHARP
using System;

class LegacyService
{
    [Obsolete("Please use NewService instead", error: false)]
    public void OldMethod() => Console.WriteLine("Old method");

    public void NewMethod() => Console.WriteLine("New method");
}

class Program
{
    static void Main()
    {
        var service = new LegacyService();
        service.OldMethod();
        service.NewMethod();
    }
}
TEXT 📖 للعرض فقط
Old method
New method
💡 عندما يتم تعيين المعلمة error الخاصة بـ Obsolete إلى true، فإن استدعاء الطريقة القديمة سيؤدي إلى ظهور خطأ في التحويل البرمجي بدلاً من تحذير.

(2) السمات المخصصة

CSHARP
using System;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
class DescriptionAttribute : Attribute
{
    public string Text { get; }
    public DescriptionAttribute(string text) => Text = text;
}

[Description("User management service")]
class UserService
{
    [Description("Get all users")]
    public void GetAll() { }
}

class Program
{
    static void Main()
    {
        var attr = Attribute.GetCustomAttribute(typeof(UserService), typeof(DescriptionAttribute)) as DescriptionAttribute;
        Console.WriteLine(attr?.Text ?? "No description");
    }
}
TEXT 📖 للعرض فقط
User management service

3. تحليل متعمق للقيود العامة

تستخدم القيود العامة الكلمة الرئيسية where لتقييد نطاق معلمات النوع، مما يضمن استيفاءها لشروط محددة.

(1) نظرة عامة على أنواع القيود

القيد الوصف
where T : class يجب أن يكون T من النوع المرجعي
where T : struct يجب أن يكون T نوعًا قيمياً (لا يمكن أن يكون قيمة فارغة)
where T : new() يجب أن تحتوي T على مُنشئ عام بدون معلمات
where T : ISpecific يجب أن تنفذ T الواجهة المحددة
where T : BaseClass يجب أن ترث T من الفئة الأساسية المحددة
where T : unmanaged يجب أن يكون T نوعًا غير مُدار
where T : notnull يجب أن يكون T نوعًا غير قابل للفراغ

▶ مثال

CSHARP
using System;

interface IRepository
{
    string GetName();
}

class SqlRepository : IRepository
{
    public string GetName() => "SQL Repository";
}

class Service```<T>``` where T : class, IRepository, new()
{
    private T _repo = new T();
    public void Print() => Console.WriteLine(_repo.GetName());
}

class Program
{
    static void Main()
    {
        var service = new Service<SqlRepository>();
        service.Print();
    }
}
▶ جرّب الكود
TEXT 📖 للعرض فقط
SQL Repository
⚠️ يجب أن يظهر القيد new() في آخر قائمة القيود؛ ويجب أن يأتي class أو struct أولاً.


4. المكررات (yield)

تستخدم أدوات التكرار yield return لإنتاج عناصر التسلسل واحدة تلو الأخرى، مما يحقق التقييم المتأخر — حيث لا يتم حساب العناصر إلا عند تكرارها.

(1) العائد على السندات وفترة انقطاع العائد

CSHARP
using System;
using System.Collections.Generic;

class Program
{
    static IEnumerable```<int>``` GetNumbers()
    {
        for (int i = 0; i < 5; i++)
        {
            if (i == 3) yield break;
            yield return i;
        }
    }

    static void Main()
    {
        foreach (int n in GetNumbers())
            Console.WriteLine(n);
    }
}
TEXT 📖 للعرض فقط
0
1
2
💡 yield break يوقف التكرار فورًا. تُرجع طرق المُكرر IEnumerable<T> أو IEnumerator<T>.

▶ مثال

CSHARP
using System;
using System.Collections.Generic;

class Program
{
    static IEnumerable```<int>``` Fibonacci(int count)
    {
        int a = 0;
        int b = 1;
        for (int i = 0; i < count; i++)
        {
            yield return a;
            int temp = a + b;
            a = b;
            b = temp;
        }
    }

    static void Main()
    {
        Console.WriteLine("Fibonacci sequence, first 10 terms:");
        foreach (int n in Fibonacci(10))
        {
            Console.Write(n + " ");
        }
        Console.WriteLine();
    }
}
▶ جرّب الكود
TEXT 📖 للعرض فقط
Fibonacci sequence, first 10 terms:
0 1 1 2 3 5 8 13 21 34 

5. Span<T> و Memory<T>

يوفر كل من Span<T> وMemory<T> وصولاً مقسَّمًا دون نسخ إلى مناطق الذاكرة المتجاورة، مما يجعلهما نوعين أساسيين في سيناريوهات الأداء العالي.

(1) الاستخدام الأساسي لـ Span<T>

CSHARP
using System;

class Program
{
    static void Main()
    {
        int[] array = { 10, 20, 30, 40, 50 };
        Span```<int>``` span = array.AsSpan();
        Span```<int>``` slice = span.Slice(1, 3);

        slice[0] = 99;

        Console.WriteLine(string.Join(", ", array));

        Span```<int>``` stackSpan = stackalloc int[3];
        stackSpan[0] = 1;
        stackSpan[1] = 2;
        stackSpan[2] = 3;
        Console.WriteLine(string.Join(", ", stackSpan.ToArray()));
    }
}
TEXT 📖 للعرض فقط
10, 99, 30, 40, 50
1, 2, 3
⚠️ لا يمكن تخزين Span<T> إلا في المكدس؛ ولا يمكن استخدامه كحقل فئة أو عبر حدود تعليق (await). استخدم Memory<T> عندما تحتاج إلى التوسع عبر إطارات المكدس.


6. التعبيرات النمطية (Regex)

تُستخدم فئة System.Text.RegularExpressions.Regex لمطابقة الأنماط والبحث عن النص واستبداله.

(1) العمليات الشائعة

CSHARP
using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        string input = "Contact phone: 138-1234-5678, Email: test@example.com";

        bool hasPhone = Regex.IsMatch(input, @"\d{3}-\d{4}-\d{4}");
        Console.WriteLine($"Contains phone: {hasPhone}");

        Match phoneMatch = Regex.Match(input, @"\d{3}-\d{4}-\d{4}");
        Console.WriteLine($"Phone: {phoneMatch.Value}");

        MatchCollection emails = Regex.Matches(input, @"[\w.]+@[\w.]+");
        foreach (Match m in emails)
            Console.WriteLine($"Email: {m.Value}");

        string replaced = Regex.Replace(input, @"\d{4}", "****");
        Console.WriteLine($"Replaced: {replaced}");
    }
}
TEXT 📖 للعرض فقط
Contains phone: True
Phone: 138-1234-5678
Email: test@example.com
Replaced: Contact phone: 138-****-****, Email: test@example.com

(2) مرجع سريع للأنماط الشائعة

النمط الوصف
\d رقم
\w حرف/رقم/شرطة سفلية
\s مسافة بيضاء
. أي حرف (باستثناء حرف نهاية السطر)
^ / $ بداية السطر / نهاية السطر
{n,m} كرر n إلى m مرات
[abc] مجموعة الأحرف

7. كود غير آمن

يسمح سياق unsafe باستخدام المؤشرات وعمليات الذاكرة اليدوية، وهو ما ينطبق على سيناريوهات التوافق أو سيناريوهات الأداء الفائق.

(1) المؤشرات والقيم الثابتة

CSHARP
using System;

class Program
{
    static unsafe void Main()
    {
        int value = 42;
        int* ptr = &value;

        Console.WriteLine($"Value: {*ptr}");
        Console.WriteLine($"Address: {(long)ptr}");

        int[] arr = { 1, 2, 3 };
        fixed (int* p = arr)
        {
            Console.WriteLine($"First element: {*p}");
            Console.WriteLine($"Second element: {*(p + 1)}");
        }
    }
}
TEXT 📖 للعرض فقط
Value: 42
Address: 12345678
First element: 1
Second element: 2
⚠️ يتطلب استخدام unsafe تمكين <AllowUnsafeBlocks>true</AllowUnsafeBlocks>`` in the project file. The fixed`؛ حيث تعمل هذه العبارة على تثبيت الكائن لمنع آلية جمع القمامة (GC) من نقل الذاكرة.


8. نظرة عامة على ميزات إصدارات لغة C# (7–12)

الإصدار الميزات الرئيسية وصف موجز
C# 7 المتغيرات ذات النوع «out»، المجموعات، مطابقة الأنماط out int x الإعلان المضمن، (int, string) المجموعات، is Type الأنماط
C# 7 الدوال المحلية، قيم الإرجاع من نوع ref الدوال المتداخلة داخل الطرق، قيم الإرجاع من نوع المرجع
C# 8 الأنواع المرجعية القابلة للقيمة «null»، التدفقات غير المتزامنة string? علامة «nullable»، IAsyncEnumerable<T>
C# 8 طرق الواجهة الافتراضية، والفهارس، والنطاقات تطبيقات الواجهة الافتراضية، [^1]، [1..3]
C# 9 أنواع السجلات، مُعيِّنات التهيئة record الأنواع غير القابلة للتغيير، init الخصائص المخصصة للتهيئة فقط
C# 9 العبارات ذات المستوى الأعلى، وnew المحددة النوع عدم وجود النص النمطي لـMain، new() حذف النوع
C# 10 استخدام "using" عالمي، مساحات الأسماء على نطاق الملف global using X;، namespace Ns; سطر واحد
C# 10 هياكل «record»، سلاسل نصية ثابتة مع إدراج قيم record struct، سلاسل نصية ثابتة مع إدراج قيم
C# 11 القيم الثابتة للسلاسل الخام، إلزامية """...""" السلاسل الخام متعددة الأسطر، required التهيئة الإجبارية
C# 11 أنماط القوائم، الثوابت UTF-8 [1, 2, ..] المطابقة، "hello"u8
C# 12 المُنشِئات الأولية class C(int x) إعلان الفئة كمُنشِئ
C# 12 تعبيرات المجموعات، الاسم المستعار لأي نوع [1, 2, 3] التهيئة الموحدة، using P = int*
💡 هذا الدرس هو لمحة عامة عن الميزات المتقدمة؛ وسيتم تناول كل موضوع بالتفصيل في درس تكميلي مخصص له.


❓ أسئلة شائعة

س هل للانعكاس تأثير سلبي على الأداء؟
ج نعم، فالانعكاس أبطأ بعشرات المرات من الاستدعاءات المباشرة. في حالة الاستخدام المتكرر، قم بتخزين MethodInfo في ذاكرة التخزين المؤقت أو انتقل إلى استخدام أشجار التعبيرات.
س ما الفرق بين Span<T> و Memory<T>؟
ج لا يمكن لـ Span أن توجد إلا في المكدس (stack) ولا يمكنها عبور حدود الأداء غير المتزامن (async) أو التخزين (storage)؛ أما Memory فيمكنها أن توجد في الذاكرة المؤقتة (heap) وعبور حدود الأداء غير المتزامن، ويتم الوصول إليها عبر .Span.
س هل تعمل آلية «yield» في بيئة متعددة الخيوط؟
ج لا، فـ«yield» هي آلية تعداد كسولة تعمل في خيط واحد — ولا يتم حساب العناصر إلا عند استدعاء الدالة MoveNext().
س متى تحتاج إلى كود غير آمن؟
ج استخدمه عندما تحتاج إلى التوافق مع لغات C/C++، أو عمليات الذاكرة غير المُدارة، أو أداءً فائقًا؛ وتجنبه في أعمال التطوير اليومية.

📖 ملخص

📝 تمارين

  1. استخدم ميزة «الانعكاس» للحصول على جميع أسماء الطرق العامة للفئة string وعرضها
  2. إنشاء سمة مخصصة [Author]، وتطبيقها على فئة، وقراءتها عبر الانعكاس
  3. اكتب دالة عامة T Create``<T>``() where T : new() تقوم بإنشاء مثيل وإرجاعه
  4. استخدم دالة yield لتنفيذ مُكرر يُنتج أول 20 حدًّا من متتابعة فيبوناتشي
  5. استخدم التعبير النمطي (Regex) للتحقق مما إذا كانت السلسلة تتوافق مع تنسيق عنوان IPv4 صحيحًا
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%