.First مقابل .FirstOrDefault في C#: متى تختار أيهما؟

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: الخوف المألوف لدى كل مطور C#

\n

تخيل الموقف: أنت تكتب استعلامًا لقاعدة بيانات أو مجموعة في الذاكرة. تحتاج إلى الحصول على العنصر الأول الذي يحقق الشرط. أنت متأكد من أن هذا العنصر موجود بالتأكيد. أم لست متأكدًا؟ هنا يبدأ الرقص مع الطبلة: .First() أم .FirstOrDefault()؟

\n

هذا السؤال هو ضربة حقيقية على Stack Overflow بآلاف المشاهدات. وليس من دون سبب. الاختيار بين هاتين الطريقتين يمكن أن يعني الفرق بين كود نظيف ومتوقع وبين استثناء InvalidOperationException مفاجئ في بيئة الإنتاج. دعنا نفهم مرة واحدة وإلى الأبد متى نستخدم أي طريقة، وننسى الشكوك إلى الأبد.

\n\n

باختصار عن الأساسيات: ما الفرق؟

\n

كلا الطريقتين تفعلان نفس الشيء تقريبًا: تعيدان العنصر الأول من التسلسل الذي يحقق الشرط (أو ببساطة العنصر الأول إذا لم يتم تحديد شرط). لكن هناك فرق جوهري:

\n
    \n
  • .First() — إذا لم يتم العثور على العنصر، فإنها ترمي استثناء System.InvalidOperationException.
  • \n
  • .FirstOrDefault() — إذا لم يتم العثور على العنصر، فإنها تعيد القيمة الافتراضية للنوع (null للأنواع المرجعية، 0 لـ int، false لـ bool، إلخ).
  • \n
\n

يبدو الأمر بسيطًا. لكن الشيطان، كما هو الحال دائمًا، يكمن في التفاصيل.

\n\n

متى نستخدم .First(): عندما "يجب أن يكون موجودًا، ولا نقاش"

\n

استخدم .First() عندما يضمن منطق عملك بشكل صارم أن العنصر موجود. إذا لم يكن موجودًا، فهذه حالة استثنائية، خطأ في البيانات أو منطق التطبيق.

\n\n

مثال 1: البحث بواسطة معرف فريد

\n

إذا كنت تبحث عن مستخدم بواسطة المفتاح الأساسي في قاعدة البيانات (مثل المعرف)، وتأكدت من وجود هذا المستخدم، استخدم .First():

\n
public class UserService\n{\n    private readonly AppDbContext _context;\n\n    public UserService(AppDbContext context)\n    {\n        _context = context;\n    }\n\n    public User GetUserById(int userId)\n    {\n        // نتوقع وجود مستخدم بهذا المعرف.\n        // إذا لم يكن موجودًا، فهذه مشكلة خطيرة، فليُرمَ الاستثناء.\n        return _context.Users.First(u => u.Id == userId);\n    }\n}
\n

الاستثناء في هذه الحالة هو إشارة إنذار. إنه يقول: "مرحبًا، البيانات تالفة، أو شخص ما أرسل معرفًا غير صحيح". ستلتقط هذا الاستثناء في مستوى أعلى من المكدس وتتعامل معه كخطأ حرج.

\n\n

مثال 2: العنصر الأول بعد الفرز (مضمون)

\n

إذا كنت تقوم بفرز قائمة وتأخذ العنصر الأول، وكانت القائمة تحتوي بالتأكيد على عناصر:

\n
var highestScore = players\n    .OrderByDescending(p => p.Score)\n    .First(); // لا يمكن أن يكون عدد اللاعبين 0، لقد تحققنا من ذلك مسبقًا
\n

إذا تحققت مسبقًا من أن المجموعة ليست فارغة (مثل if (players.Any()))، فإن .First() هو اختيارك.

\n\n

متى نستخدم .FirstOrDefault(): عندما قد لا يكون العنصر موجودًا

\n

القاعدة الذهبية: إذا كان غياب النتيجة هو وضع طبيعي وليس خطأ، استخدم .FirstOrDefault().

\n\n

مثال 1: بحث اختياري

\n

تخيل أننا نبحث عن طلب برقم، ولكن الطلب قد لا يكون قد تم إنشاؤه بعد:

\n
public Order FindOrderByNumber(string orderNumber)\n{\n    // قد لا يكون الطلب موجودًا. هذا طبيعي.\n    return _context.Orders\n        .FirstOrDefault(o => o.OrderNumber == orderNumber);\n    // سيعيد null إذا لم يتم العثور على الطلب.\n}
\n

بعد استدعاء هذه الطريقة، يجب علينا التحقق من النتيجة للتأكد من أنها ليست null:

\n
var order = FindOrderByNumber("ORD-12345");\nif (order != null)\n{\n    // نعمل مع الطلب\n    Console.WriteLine($"تم العثور على الطلب: {order.Id}");\n}\nelse\n{\n    Console.WriteLine("لم يتم العثور على الطلب. يتم إنشاء طلب جديد.");                

المدونات

توصيات الكتب