سلام با یکی دیگر از آموزش های LINQ در خدمت شما عزیزان هستیم در این جلسه& آموزش اپراتورهای Element را بررسی خواهیم کرد.
یکی از ساده ترین مبحث های LINQ، اپراتورهای Element هستند که کاربرد کلی آن ها برای بازگرداندن اولین یا آخرین عنصر یک مجموعه با روش های مختلف است
در ادامه با آن ها آشنا خواهیم شد.
اپراتورهای Element به شرح زیر هستند:
First
FirstOrDefault
Last
LastOrDefault
ElementAt
ElementAtOrDefault
Single
SingleOrDefault
DefaultIfEmpty
که خلاصه ی کاربرد آن ها مطابق جدول زیر است:
کاربرد | نام اپراتور |
عنصر اول یک مجموعه را باز می گرداند | First |
کاملا مانند First است اما در صورت خالی بودن مجموعه مقدار 0 را باز می گرداند |
FirstOrDefault |
عنصر آخر یک مجموعه را باز می گرداند | Last |
کاملا مانند Last است اما در صورت خالی بودن مجموعه مقدار 0 را باز می گرداند |
LastOrDefault |
عنصر nام یک مجموعه را باز می گرداند | ElementAt |
کاملا مانند ElementAt است اما در صورت خالی بودن مجموعه مقدار 0 را باز می گرداند |
ElementAtOrDefault |
عنصر خاصی را از مجموعه باز می گرداند | Single |
مانند Single اما در صورت خالی بودن مجموعه مقدار 0 را باز می گرداند | SingleOrDefault |
اگر مقادیر خالی یا صفر شامل لیست یا مجموعه باشد، مقادیر پیش فرض را برمی گرداند | DefaultIfEmpty |
این متد عنصر اول یک مجموعه را باز می گرداند اما اگر شرطی در آن قرار داده شود اولین عنصری که در شرط صدق می کند را باز می گرداند.
الگوی استفاده از آن به صورت زیر است:
var result = objList.First();
توجه کنید نوع داده ی result
از نوع داده ی objList
خواهد بود.
به مثال زیر توجه کنید:
using System; using System.Linq; namespace LINQExamples { class Program { static void Main(string[] args) { int[] objList = { 1, 2, 3, 4, 5 }; int result = objList.First(); Console.WriteLine("Element from the List: {0}", result); Console.ReadLine(); } } }
در این مثال نوع داده ی آرایه از نوع int
است پس وقتی شی objList
متد First
را فراخوانی می کند، جنس خروجی آن (result)
از نوع int
خواهد بود.
در این مورد متد First
بدون پارامتر به کار برده شده در نتیجه عنصر اول آرایه را باز می گرداند. حالا فرض کنید در متد First
شرطی را به صورت زیر وارد کنیم:
int result = objList.First(x =>x%2==0);
در این حالت اولین عنصری که زوج است به عنوان خروجی در نظر گرفته می شود که در این مورد عدد 2 خواهد بود.
به مثال دوم از کاربرد First
توجه کنید:
using System; using System.Collections.Generic; using System.Linq; namespace LINQExamples { class Program { static void Main(string[] args) { List<Student> stu = new List<Student> { new Student(){ID=1,Name="Jack" }, new Student(){ID=2,Name="Harry" }, new Student(){ID=3,Name="Jacob" }, }; Student result = stu.First(x =>x.ID%2==0); Console.WriteLine("Element from the List: {0} ID={1}", result.Name,result.ID); Console.ReadLine(); } } public class Student { public int ID { get; set; } public string Name { get; set; } } }
در این مثال عناصر موجود در List
از جنس کلاس Student
هستند که ما قصد داریم اولین شخصی که ID
آن زوج است را در خروجی نشان دهیم. با دقت بسیار به نوع داده ی result
توجه کنید.
خروجی:
Element from the List: Harry ID=2
بازنویسی کد به روش Query به صورت زیر است:
Student result = (from st in stu select st).First(x => x.ID % 2 == 0);
قبل از توضیح این متد، در IDE خود یکی از مثال های متد First
را به گونه ای تغییر دهید که First
بر روی یک List
یا آرایه ی خالی از عنصر اعمال شود. خواهید دید که با Run کردن، برنامه با exception مواجه می شوبد. راه حل این مشکل استفاده از متد FirstOrDefault
است. در واقع کاربرد آن کاملا مشابه با First
است حتی می توانید در دو مثال مربوط به First
به جای آن از FirstOrDefault
استفاده کنید. اما استفاده از این متد یک مزیت به همراه دارد که در صورت خالی بودن مجموعه، برنامه با exception مواجه نمی شود و مقدار پیش فرض صفر را باز می گرداند.
به مثال زیر توجه کنید:
using System; using System.Linq; namespace LINQExamples { class Program { static void Main(string[] args) { int[] objList = { 1, 2, 3, 4, 5 }; int[] objVals = { }; int result = objList.FirstOrDefault(); int val = objVals.FirstOrDefault(); Console.WriteLine("Element from the List1: {0}", result); Console.WriteLine("Element from the List2: {0}", val); Console.ReadLine(); } } }
کد بالا را اجرا کنید، خواهید دید که با این که objVals
خالی از عنصر است اما برنامه بدون exception اجرا شده و مقدار پیش فرض صفر برای آرایه ی خالی در نظر گرفته می شود.
از نظر کارکرد کاملا شبیه به متد First
است با این تفاوت که متد First
از اول یک مجموعه (سمت چپ) کار خود را شروع می کند اما متد Last
از آخر یک مجموعه (سمت راست) آغاز به کار می کند.
الگوی استفاده از آن به صورت زیر است:
var result = objList.Last();
توجه داشته باشید که نوع داده ی var به نوع داده ی objList
بستگی دارد.
به مثال زیر توجه کنید:
using System; using System.Linq; namespace LINQExamples { class Program { static void Main(string[] args) { int[] objList = {1,2,3,4,5,6,7,8,9}; int result = objList.LastOrDefault(x=>x%2==0); Console.WriteLine("Element from the List1: {0}", result); Console.ReadLine(); } } }
خروجی آن عدد 8 خواهد بود زیرا متد Last
از آخر آرایه شروع به پیمایش می کند و اولین عنصری که زوج است را باز می گرداند.
بازنویسی کد به روش Query به صورت زیر است:
int result = (from x in objList select x).Last(x =>x%2==0);
این متد نیز مانند FirstOrDefault
عمل می کند اما جهت پیمایش مجموعه را از سمت راست شروع می کند و در صورت خالی بودن مجموعه عدد صفر را باز می گرداند.
کد زیر را در IDE خود بنویسید:
using System; using System.Linq; namespace LINQExamples { class Program { static void Main(string[] args) { int[] objList = {1,3,5,7,9,13}; int result = objList.Last(x=>x%2==0); Console.WriteLine("Element from the List1: {0}", result); Console.ReadLine(); } } }
حال آن را اجرا کنید، خواهید دید که با exception مواجه می شوید اما دلیل آن چیست؟
در این مورد شرط ما بازگرداندن آخرین عنصر زوج یک مجموعه است. همان طور که مشاهده می کنید تمامی عناصر موجود در آرایه فرد هستند پس با وجود شرط، آرایه ی موجود، یک آرایه ی خالی به حساب می آید. برای این که در اجرای کد بالا به exception برخورد نکنیم لازم است با استفاده از متد FirstOrDefault
کد را باز نویسی کنیم تنها کافی است Last
را به FirstOrDefault
تغییر دهید.
روش Extension:
int result = objList.LastOrDefault(x=>x%2==0);
روش Query:
int result = (from x in objList select x).LastOrDefault(x => x % 2 == 0);
با اعمال تغییر، دوباره کد را اجرا کنید. خواهید دید که این بار خروجی مقدار صفر خواهد یود.
کاربرد این متد بسیار ساده بوده و تنها ورودی آن پارامتری از جنس int
است و با توجه به عدد وارد شده در آن، عنصری را به عنوان خروجی در نظر می گیرد.
الگوی استفاده از آن به صورت زیر است:
var result = objList.ElementAt(1);
توجه کنید که نوع داده ی var
به نوع داده ی objList
بستگی دارد.
مثال:
using System; using System.Collections.Generic; using System.Linq; namespace LINQExamples { class Program { static void Main(string[] args) { List<Student> stu = new List<Student> { new Student(){ID=1,Name="Jack" }, new Student(){ID=2,Name="Harry" }, new Student(){ID=3,Name="Jacob" }, }; Student result = stu.ElementAt(2); Console.WriteLine("Element from the List: {0} ID={1}", result.Name, result.ID); Console.ReadLine(); } } public class Student { public int ID { get; set; } public string Name { get; set; } } }
در این مثال با استفاده ار متد ElementAt
قصد داریم عنصر سوم از List
را در خروجی چاپ کنیم. دقت به این نکته ضروری است که شمارنده ی متد ElementAt
از 0 شروع می شود بنابراین در این مثال برای دستیابی به عنصر شماره سوم باید عدد 2 را در ElementAt
وارد کنیم که در نتیجه ی آن خروجی به صورت
Element from the List: Jacob ID=3
خواهد شد.
برای پیاده سازی کد به روش Query به صورت عمل می کنیم:
Student result = (from x in stu select x).ElementAt(2);
به مثالی دیگر از کاربرد متد ElementAt
توجه کنید:
using System; using System.Linq; namespace LINQExamples { class Program { static void Main(string[] args) { int[] objList = { 1, 2, 3, 4, 5 }; int result = objList.ElementAt(1); int val = objList.ElementAt(3); Console.WriteLine("Element At Index 1: {0}", result); Console.WriteLine("Element At Index 3: {0}", val); Console.ReadLine(); } } }
روش Query:
int result = (from x in objList select x).ElementAt(1); int val = (from x in objList select x).ElementAt(3);
این متد شباهت بسیار زیادی به متد ElementAt
دارد با این تفاوت که اگر توسط یک مجموعه خالی از عضو فراخوانی شود، برنامه با exception مواجه نمی شود و مقدار پیش فرض را صفر در نظر می گیرد.
الگوی استفاده از آن به صورت زیر است:
var result = objList.ElementAtOrDefault(1);
توجه کنید که نوع داده ی var
به نوع داده ی objList
بستگی دارد.
مثال:
using System; using System.Linq; namespace LINQExamples { class Program { static void Main(string[] args) { int[] objList = {1,2,3,4,5}; int result = objList.ElementAtOrDefault(1); int val = objList.ElementAtOrDefault(3); int val1 = objList.ElementAtOrDefault(10); Console.WriteLine("Element At Index 1: {0}", result); Console.WriteLine("Element At Index 3: {0}", val); Console.WriteLine("Element At Index 10: {0}", val1); Console.ReadLine(); } } }
برنامه را اجرا و خروجی را مشاهده کنید. در مورد result
و val
، اعداد وارد شده در متد ElementAtOrDefault
جز ایندکس آرایه objList
هستند. پس عضو متناظر با آن در خروجی چاپ شده است. در مورد val1
که عضو یازدهم در خواست شده اما در آرایه، پنج عضو وجود دارد. چون از متد ElementAtOrDefault
استفاده شده، روند اجرای برنامه با مشکل روبرو نخواهد شد و مقدار صفر را در خروجی چاپ می کند.
روش Query:
int result = (from x in objList select x).ElementAtOrDefault(1); int val = (from x in objList select x).ElementAtOrDefault(3); int val1 = (from x in objList select x).ElementAtOrDefault(10);
از این اپراتور برای بازگرداندن یک عنصر از مجموعه یا یک عنصر که در شرط صدق کند، استفاده می شود. در صورتی که بیش از یک عضو در مجموعه موجود باشد یا اصلا عضوی در مجموعه موجود نباشد خطای InvalidOperationException
پرتاب می کند.
الگوی استفاده از آن به صورت زیر است:
var val = objList.Single();
توجه کنید که نوع داده ی var
به نوع داده ی objList
بستگی دارد.
برای درک بهتر این متد به مثال زیر توجه کنید:
using System; using System.Linq; using System.Collections.Generic; namespace LINQExamples { class Program { static void Main(string[] args) { List<Student> objStudent = new List<Student>() { new Student() { Name = "Suresh Dasari", Gender = "Male",Location="Chennai" }, new Student() { Name = "Rohini Alavala", Gender = "Female", Location="Chennai" }, new Student() { Name = "Praveen Alavala", Gender = "Male",Location="Bangalore" }, new Student() { Name = "Sateesh Alavala", Gender = "Male", Location ="Vizag"}, new Student() { Name = "Madhav Sai", Gender = "Male", Location="Nagpur"} }; int[] objList = {2}; var user = objStudent.Single(s => s.Name == "Suresh Dasari"); string result = user.Name; int val = objList.Single(); Console.WriteLine("Element from objStudent: {0}", result); Console.WriteLine("Element from objList: {0}", val); Console.ReadLine(); } } class Student { public string Name { get; set; } public string Gender { get; set; } public string Location { get; set; } } }
در این مثال، ابتدا شی از لیستی که اعضای آن از جنس کلاس Student هستند، تعریف شده است. با استفاده از متد Single
شرط یکتا بودن نام Suresh Dasari را در لیست چک کرده ایم که در صورت درست بودن شرط همان مقدار در خروجی چاپ می شود، در غیر این صورت خطای InvalidOperationException
پرتاب می شود.
حالا به objList
دقت کنید که یک آرایه از نوع int
با یک عضو تعریف شده و در ادامه با استفاده از متد Single
شرط تک عضوی بودن آرایه چک شده است. بنابراین مقدار عنصر موجود در آرایه به عنوان خروجی چاپ می شود. توجه داشته باشید خروجی برنامه خطای InvalidOperationException
خواهد بود اگر یکی از حالت های زیر پیش آید:
حالت اول:
int[] objList = {2,5,6};
یا
int[] objList = {2,2};
یا
int[] objList = {};
حالت دوم:
List<Student> objStudent = new List<Student>() { new Student() { Name = "Suresh Dasari", Gender = "Male",Location="Chennai" }, new Student() { Name = "Suresh Dasari", Gender = "Female", Location="Chennai" }, new Student() { Name = "Suresh Dasari", Gender = "Male",Location="Bangalore" }, new Student() { Name = "Sateesh Alavala", Gender = "Male", Location ="Vizag"}, new Student() { Name = "Madhav Sai", Gender = "Male", Location="Nagpur"} };
یا
List<Student> objStudent = new List<Student>(){};
برای بازنویسی کد به روش Query به این صورت عمل می کنیم:
var user = (from stu in objStudent select stu).Single(s =>s.Name== "Suresh Dasari"); int val = (from x in objList select x).Single();
در مورد متد Single
به یاد دارید که در دو حالت خالی بودن مجموعه و وجود بیش از یک عضو خطای InvalidOperationException
توسط این متد پرتاب می شود. در مورد متد SingleOrDefault
کاملا به همین صورت است، فقط خالی بودن مجموعه از عضو، باعث بروز خطای InvalidOperationException
نمی شود.
الگوی استفاده از متد SingleOrDefault
به صورت زیر است:
var val = objList.SingleOrDefault();
توجه کنید که نوع داده ی var
به نوع داده ی objList
بستگی دارد.
مثال:
using System; using System.Linq; using System.Collections.Generic; namespace LINQExamples { class Program { static void Main(string[] args) { List<Student> objStudent = new List<Student>() { new Student() { Name = "Suresh Dasari", Gender = "Male",Location="Chennai" }, new Student() { Name = "Rohini Alavala", Gender = "Female", Location="Chennai" }, new Student() { Name = "Praveen Alavala", Gender = "Male",Location="Bangalore" }, new Student() { Name = "Sateesh Alavala", Gender = "Male", Location ="Vizag"}, new Student() { Name = "Madhav Sai", Gender = "Male", Location="Nagpur"} }; int[] objList = { 1, 2, 3, 4, 5 }; int[] objList2 = {}; var user = objStudent.SingleOrDefault(i => i.Name == "Suresh Dasari"); string result = user.Name; int val = objList.SingleOrDefault(j => j > 5); int val2 = objList2.SingleOrDefault(); Console.WriteLine("Element from objStudent: {0}", result); Console.WriteLine("Element from objList: {0}", val); Console.WriteLine("Element from objList: {0}", val2); Console.ReadLine(); } } class Student { public string Name { get; set; } public string Gender { get; set; } public string Location { get; set; } } }
مشاهده می کنید که در آرایه ی objList
عضوی بزرگ تر از 5 وجود ندارد در حالی که شرط قرار داده شده بر روی آن به صورت (SingleOrDefault(j => j > 5
است. در صورتی که از متد Single
استفاده کنیم با خطا روبرو می شویم اما SingleOrDefault
در صورت موجود نبودن عضو مورد نظر، خروجی صفر نمایش داده می شود.
در مورد آرایه ی objList2
هم به همین صورت است، متد SingleOrDefault
بر روی یک آرایه ی خالی از عضو فراخوانی شده، پس خروجی آن صفر است.
روش Query:
int val = (from x in objList select x).SingleOrDefault(j =>j>5); int val2 = (from x in objList2 select x).SingleOrDefault();
این متد اگر بر روی یک مجموعه ی عادی دارای عضو فراخوانی شود، به نوعی کار Select
را انجام می دهد و تمامی عناصر توسط یک حلقه قابل دستیابی هستند اما اگر بر روی یک مجموعه ی خالی از عضو یا به طور کلی بر روی یک شی تهی فراخوانی شود، روند اجرای برنامه متفاوت خواهد بود که حالت های مختلف آن را بر روی یک مثال بررسی خواهیم کرد.
الگوی استفاده از آن به صورت زیر است:
var result = List1.DefaultIfEmpty();
به مثال زیر توجه کنید:
using System; using System.Linq; using System.Collections.Generic; namespace LINQExamples { class Program { static void Main(string[] args) { int[] List1 = { 1, 2, 3, 4, 5 }; int[] List2 = { }; var result1 = List1.DefaultIfEmpty(); var result2 = List2.DefaultIfEmpty(); var result3 = List2.DefaultIfEmpty(5); Console.WriteLine("----List1 with Values----"); foreach (var val1 in result1) { Console.WriteLine(val1); } Console.WriteLine("---List2 without Values---"); foreach (var val2 in result2) { Console.WriteLine(val2); } Console.WriteLine("---List2 without Values---"); foreach (var val3 in result3) { Console.WriteLine(val3); } Console.ReadLine(); } } }
همان طور که در بالا ذکر شد اگر متد DefaultIfEmpty
بر روی یک مجموعه ی دارای عضو فراخوانی شود کار Select
را انجام می دهد، که صحت این موضوع را می توان با دقت به آرایه ی List1
و خروجی تایید کرد. اما به آرایه ی List2
دقت کنید که خالی از عضو است. در حالت اول متد DefaultIfEmpty
بدون پارامتر ورودی فراخوانی شده، پس مقدار صفر در خروجی نمایان می شود. در حالت دوم دوباره متد DefaultIfEmpty
توسط List2
فراخوانی شده اما این بار متد، یک پارامتر ورودی دلخواه دارد و کاربرد آن بدین صورت است که در صورت خالی بودن مجموعه، پارامتر وردی متد DefaultIfEmpty
در خروجی چاپ می شود.
روش Query:
var result1 = (from x in List1 select x).DefaultIfEmpty(); var result2 = (from x in List2 select x).DefaultIfEmpty(); var result3 = (from x in List2 select x).DefaultIfEmpty(5);
این بخش از آموزش به پایان رسید. سعی کنید با استفاده از متد های بررسی شده در این بخش مثال های متعددی حل کنید چون این متدها علی رغم سادگی فرار هستند و نیاز به تمرین و تکرار دارند.
موفق باشید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.