أدوات عامة قابلة لإعادة الاستخدام
أنشئ مساعدات صغيرة قابلة لإعادة الاستخدام: فحوصات Guard، ومقارن مساواة قائمًا على المفتاح، وحفظًا مؤقتًا للدوال النقية، وResult بسيطًا.
أدوات عامة قابلة لإعادة الاستخدام درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 3 من أصل 3. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 3 دروس في المجموع.
خطة حزمة الأدوات
الهدف: اجمع مساعدات صغيرة يمكنك إعادة استخدامها عبر المشاريع.
- فحوصات Guard للوسائط
- مقارن قائم على المفتاح للمساواة
- احفظ نتيجة دالة صرفة باستخدام Memoize
- Result<T> للتعامل مع مساري النجاح والخطأ
فحوصات Guard
اجمع التحقق من الوسائط في صنف Guard صغير؛ واستدعِه عند بدء الأسلوب.
using System;
public static class Guard
{
public static T NotNull<T>(T value, string name) where T : class
{
if (value == null) throw new ArgumentNullException(name);
return value;
}
public static string NotNullOrEmpty(string value, string name)
{
if (string.IsNullOrEmpty(value)) throw new ArgumentException("must not be null or empty", name);
return value;
}
}
public class Program
{
public static void Main(string[] args)
{
// OK
string name = Guard.NotNullOrEmpty("Ada", "name");
Console.WriteLine("Hello, " + name);
// Uncomment to see guard throw:
// Guard.NotNull<string>(null, "input");
}
}
مقارن قائم على المفتاح
قارن الكائنات المعقدة باستخدام مفتاح (مثل Id) من دون المساس بـ Equals/GetHashCode الخاص بالنموذج.
using System;
using System.Collections.Generic;
public sealed class KeyEqualityComparer<T, TKey> : IEqualityComparer<T>
{
private readonly Func<T, TKey> _keySelector;
private readonly IEqualityComparer<TKey> _keyComparer;
public KeyEqualityComparer(Func<T, TKey> keySelector)
: this(keySelector, EqualityComparer<TKey>.Default) {}
public KeyEqualityComparer(Func<T, TKey> keySelector, IEqualityComparer<TKey> keyComparer)
{
if (keySelector == null) throw new ArgumentNullException("keySelector");
if (keyComparer == null) throw new ArgumentNullException("keyComparer");
_keySelector = keySelector;
_keyComparer = keyComparer;
}
public bool Equals(T x, T y)
{
if (object.ReferenceEquals(x, y)) return true;
if ((object)x == null || (object)y == null) return false;
return _keyComparer.Equals(_keySelector(x), _keySelector(y));
}
public int GetHashCode(T obj)
{
if ((object)obj == null) return 0;
TKey key = _keySelector(obj);
return key == null ? 0 : _keyComparer.GetHashCode(key);
}
}
public sealed class User
{
public int Id;
public string Name;
}
public class Program
{
public static void Main(string[] args)
{
List<User> list = new List<User>();
list.Add(new User { Id = 1, Name = "Ada" });
list.Add(new User { Id = 1, Name = "Ada Lovelace" }); // same Id -> considered equal
list.Add(new User { Id = 2, Name = "Alan" });
// Deduplicate by Id using a HashSet with our comparer
HashSet<User> set = new HashSet<User>(new KeyEqualityComparer<User,int>(delegate(User u) { return u.Id; }));
foreach (User u in list) set.Add(u);
Console.WriteLine("Unique by Id = " + set.Count); // 2
}
}
مساعد Memoization
يخزّن Memoize نتائج الدالة الصرفة مؤقتًا. استخدمه عند تكرار الاستدعاءات بالمدخل نفسه.
using System;
using System.Collections.Generic;
public static class Memo
{
// Wrap a pure function f: K -> V with a simple cache
public static Func<TKey, TValue> Memoize<TKey, TValue>(Func<TKey, TValue> f)
{
if (f == null) throw new ArgumentNullException("f");
Dictionary<TKey, TValue> cache = new Dictionary<TKey, TValue>();
return delegate(TKey key)
{
TValue v;
if (cache.TryGetValue(key, out v)) return v;
v = f(key);
cache[key] = v;
return v;
};
}
}
public class Program
{
static int SlowSquare(int x)
{
// Simulate work
System.Threading.Thread.Sleep(100);
return x * x;
}
public static void Main(string[] args)
{
Func<int,int> fast = Memo.Memoize<int,int>(SlowSquare);
var t1 = DateTime.UtcNow; Console.WriteLine(fast(12));
var t2 = DateTime.UtcNow; Console.WriteLine(fast(12)); // from cache
var dt1 = (t2 - t1).TotalMilliseconds;
var t3 = DateTime.UtcNow; Console.WriteLine(fast(12)); // from cache again
var t4 = DateTime.UtcNow; var dt2 = (t4 - t3).TotalMilliseconds;
Console.WriteLine("First vs cached ms: " + dt1 + " / " + dt2);
}
}
غلاف Result<T>
يجعل النوع Result<T> المصغّر النجاح والخطأ واضحين، ويسهّل طباعتهما أو اختبارهما.
using System;
public enum ResultKind { Ok, Error }
public sealed class Result<T>
{
public ResultKind Kind;
public T Value; // valid when Ok
public string Error; // valid when Error
private Result() {}
public static Result<T> Ok(T value)
{
Result<T> r = new Result<T>();
r.Kind = ResultKind.Ok;
r.Value = value;
r.Error = null;
return r;
}
public static Result<T> Fail(string error)
{
if (string.IsNullOrEmpty(error)) throw new ArgumentException("error");
Result<T> r = new Result<T>();
r.Kind = ResultKind.Error;
r.Error = error;
r.Value = default(T);
return r;
}
public override string ToString()
{
return Kind == ResultKind.Ok ? "OK: " + (Value == null ? "null" : Value.ToString())
: "ERROR: " + Error;
}
}
public class Program
{
static Result<int> ParsePositiveInt(string s)
{
int n;
if (!Int32.TryParse(s, out n)) return Result<int>.Fail("not a number");
if (n <= 0) return Result<int>.Fail("must be > 0");
return Result<int>.Ok(n);
}
public static void Main(string[] args)
{
Console.WriteLine(ParsePositiveInt("12"));
Console.WriteLine(ParsePositiveInt("-1"));
Console.WriteLine(ParsePositiveInt("x"));
}
}
نصائح عملية
نصائح:
- اجعل المساعدات صغيرة ومركّزة.
- سمّها بوضوح: Guard وKeyEqualityComparer وMemo.
- وثّق القيود ومتى تُستخدم (الدوال الصرفة مع Memo).
- اكتب اختبار وحدة سريعًا لكل مساعد.
فائدة المقارن القائم على المفتاح
مراجعة
مراجعة: أعد استخدام الأدوات الصغيرة—Guard للمدخلات، وKeyEqualityComparer للمساواة، وMemo للدوال الصرفة، وResult<T> للنتائج الصريحة.
الأسئلة الشائعة
هل درس «أدوات عامة قابلة لإعادة الاستخدام» مجاني؟
نعم — نص درس «أدوات عامة قابلة لإعادة الاستخدام» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 3 دروس في المجموع.
ماذا ستتعلم في «أدوات عامة قابلة لإعادة الاستخدام»؟
أنشئ مساعدات صغيرة قابلة لإعادة الاستخدام: فحوصات Guard، ومقارن مساواة قائمًا على المفتاح، وحفظًا مؤقتًا للدوال النقية، وResult بسيطًا. تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟
لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 3.
كم من الوقت يستغرق درس «أدوات عامة قابلة لإعادة الاستخدام»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟
نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- unmanaged وnotnull وnew() (محاكاة C# 6)
- الرياضيات العامة (نظرة عامة) والسمات العامة (عند الحاجة)
- أدوات عامة قابلة لإعادة الاستخدام