0Pricing
C# Academy · درس

سيناريوهات البرمجة الوصفية الخفيفة

أنشئ مساعدات مدفوعة بالسمات: تسميات العرض، والتحقق من الحقول المطلوبة، ومنشئ مثيلات صغير، وتسلسلاً شبيهًا بـ CSV مع نصائح واضحة للسلامة.

سيناريوهات البرمجة الوصفية الخفيفة درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 3 من أصل 3. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 3 دروس في المجموع.

الخطة والنطاق

الهدف: توجيه سلوكيات صغيرة باستخدام السمات.

  • تعيين التسميات
  • التحقق من الحقول المطلوبة
  • منشّط DI مصغّر
  • تسلسل البيانات إلى نص شبيه بـ CSV

تسميات السمات

أضف سمة DisplayName إلى الخصائص، ثم استخدم الانعكاس لطباعة تسميات واضحة للمستخدم.

using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Property)]
public sealed class DisplayNameAttribute : Attribute
{
  public string Text { get; private set; }
  public DisplayNameAttribute(string text) { Text = text; }
}

public sealed class User
{
  [DisplayName("User Id")]
  public int Id { get; set; }

  [DisplayName("Full Name")]
  public string Name { get; set; }
}

public class Program
{
  static void PrintWithLabels(object o)
  {
    if (o == null) throw new ArgumentNullException("o");
    Type t = o.GetType();
    foreach (PropertyInfo p in t.GetProperties())
    {
      object[] at = p.GetCustomAttributes(typeof(DisplayNameAttribute), false);
      string label = at.Length > 0 ? ((DisplayNameAttribute)at[0]).Text : p.Name;
      object val = p.GetValue(o, null);
      Console.WriteLine(label + ": " + (val == null ? "null" : val.ToString()));
    }
  }

  public static void Main(string[] args)
  {
    User u = new User { Id = 1, Name = "Ada" };
    PrintWithLabels(u);
  }
}

التحقق باستخدام السمات

ضع السمة Required على الخصائص؛ إذ يتحقق مدقّق صغير منها ويبلغ عن أول حقل مفقود.

using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Property)]
public sealed class RequiredAttribute : Attribute { }

public sealed class Product
{
  [Required] public string Name { get; set; }
  public decimal Price { get; set; }
}

public class Program
{
  static bool Validate(object obj, out string error)
  {
    error = null;
    if (obj == null) { error = "object is null"; return false; }

    Type t = obj.GetType();
    foreach (PropertyInfo p in t.GetProperties())
    {
      object[] req = p.GetCustomAttributes(typeof(RequiredAttribute), false);
      if (req.Length > 0)
      {
        object v = p.GetValue(obj, null);
        if (v == null || (v is string && string.IsNullOrEmpty((string)v)))
        {
          error = "Required property missing: " + p.Name;
          return false;
        }
      }
    }
    return true;
  }

  public static void Main(string[] args)
  {
    Product ok = new Product { Name = "Mouse", Price = 10m };
    Product bad = new Product { Name = null, Price = 5m };

    string e;
    Console.WriteLine(Validate(ok, out e) ? "OK" : e);
    Console.WriteLine(Validate(bad, out e) ? "OK" : e);
  }
}

منشّط مصغّر

يربط المنشّط المصغّر اسمًا بكل معامل في المُنشئ. وفّر قيمًا افتراضية عند غيابها.

using System;
using System.Reflection;
using System.Collections.Generic;

public sealed class Repo { public string Name; public Repo(string name){ Name = name; } }

public sealed class Service
{
  public Repo R; public int Timeout;
  public Service(Repo repo, int timeout){ R = repo; Timeout = timeout; }
}

public class Program
{
  static object CreateWithArgs(Type t, IDictionary<string, object> args)
  {
    if (t == null) throw new ArgumentNullException("t");
    if (args == null) args = new Dictionary<string, object>();

    ConstructorInfo[] ctors = t.GetConstructors();
    if (ctors.Length == 0) throw new InvalidOperationException("No public constructor");

    ConstructorInfo ci = ctors[0];
    ParameterInfo[] ps = ci.GetParameters();
    object[] argv = new object[ps.Length];

    for (int i = 0; i < ps.Length; i++)
    {
      object val;
      if (args.TryGetValue(ps[i].Name, out val)) argv[i] = val;
      else if (ps[i].ParameterType.IsValueType) argv[i] = Activator.CreateInstance(ps[i].ParameterType);
      else argv[i] = null;
    }
    return ci.Invoke(argv);
  }

  public static void Main(string[] args)
  {
    IDictionary<string, object> map = new Dictionary<string, object>();
    map["repo"] = new Repo("Main");
    map["timeout"] = 30;

    Service s = (Service)CreateWithArgs(typeof(Service), map);
    Console.WriteLine(s.R.Name + " / " + s.Timeout);
  }
}

CSV باستخدام السمات

رتّب الأعمدة باستخدام CsvOrder، وقم بإفلات الفواصل وعلامات الاقتباس بصورة صحيحة.

using System;
using System.Reflection;
using System.Text;
using System.Globalization;

[AttributeUsage(AttributeTargets.Property)]
public sealed class CsvOrderAttribute : Attribute
{
  public int Index { get; private set; }
  public CsvOrderAttribute(int index){ Index = index; }
}

public sealed class Row
{
  [CsvOrder(0)] public int Id { get; set; }
  [CsvOrder(1)] public string Name { get; set; }
  [CsvOrder(2)] public decimal Price { get; set; }
}

public class Program
{
  static int GetIndex(PropertyInfo p)
  {
    object[] at = p.GetCustomAttributes(typeof(CsvOrderAttribute), false);
    return at.Length > 0 ? ((CsvOrderAttribute)at[0]).Index : Int32.MaxValue;
  }

  static string ToCsv(object o)
  {
    if (o == null) throw new ArgumentNullException("o");
    Type t = o.GetType();
    PropertyInfo[] props = t.GetProperties();

    Array.Sort(props, delegate(PropertyInfo a, PropertyInfo b)
    {
      int ia = GetIndex(a), ib = GetIndex(b);
      return ia.CompareTo(ib);
    });

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < props.Length; i++)
    {
      object v = props[i].GetValue(o, null);
      string cell = v == null ? "" : Convert.ToString(v, CultureInfo.InvariantCulture);

      if (i > 0) sb.Append(",");
      sb.Append(cell);
    }
    return sb.ToString();
  }

  public static void Main(string[] args)
  {
    Row r = new Row { Id = 7, Name = "Cable, HDMI", Price = 12.5m };
    Console.WriteLine(ToCsv(r));
  }
}

نصائح واحتياطات

نصائح:

  • فضّل typeof والبيانات الوصفية المخزّنة مؤقتًا في مسارات التنفيذ الحساسة للأداء.
  • تحقق من الأعضاء قبل استخدام GetValue أو Invoke.
  • اجعل المساعدات صغيرة واختبرها باختبارات الوحدات.
  • أوقف التنفيذ مبكرًا مع عرض رسائل مفيدة.

إرشادات الانعكاس

تحقق سريع: ما القاعدة الآمنة عند استخدام الانعكاس لتنفيذ برمجة وصفية خفيفة؟

مراجعة

مراجعة: يمكن للسمات توجيه أدوات التحويل وأدوات التحقق والمنشّطات وأدوات التسلسل الصغيرة. اجعل استخدام الانعكاس محدودًا وآمنًا.

الأسئلة الشائعة

هل درس «سيناريوهات البرمجة الوصفية الخفيفة» مجاني؟

نعم — نص درس «سيناريوهات البرمجة الوصفية الخفيفة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 3 دروس في المجموع.

ماذا ستتعلم في «سيناريوهات البرمجة الوصفية الخفيفة»؟

أنشئ مساعدات مدفوعة بالسمات: تسميات العرض، والتحقق من الحقول المطلوبة، ومنشئ مثيلات صغير، وتسلسلاً شبيهًا بـ CSV مع نصائح واضحة للسلامة. تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟

لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 3.

كم من الوقت يستغرق درس «سيناريوهات البرمجة الوصفية الخفيفة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟

نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. Type وMethodInfo والتنشيط والسمات المخصصة
  2. معلومات مستوى المصدر (سمات Caller)
  3. سيناريوهات البرمجة الوصفية الخفيفة
← العودة إلى C# Academy