سلام با یکی دیگر از آموزش های LINQ در خدمت شما عزیزان هستیم در این جلسه& آموزش اپراتورهای Element را بررسی خواهیم کرد.
یکی از ساده ترین مبحث های LINQ، اپراتورهای Element هستند که کاربرد کلی آن ها برای بازگرداندن اولین یا آخرین عنصر یک مجموعه با روش های مختلف است
در ادامه با آن ها آشنا خواهیم شد.
اپراتورهای Element به شرح زیر هستند:
FirstFirstOrDefaultLastLastOrDefaultElementAtElementAtOrDefaultSingleSingleOrDefaultDefaultIfEmptyکه خلاصه ی کاربرد آن ها مطابق جدول زیر است:
| کاربرد | نام اپراتور |
| عنصر اول یک مجموعه را باز می گرداند | 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);

این بخش از آموزش به پایان رسید. سعی کنید با استفاده از متد های بررسی شده در این بخش مثال های متعددی حل کنید چون این متدها علی رغم سادگی فرار هستند و نیاز به تمرین و تکرار دارند.
موفق باشید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.