محتویات سایت
        برچسب های محبوب 








 
   معرفی اپراتور های Cast و OfType در زبان LINQ
  در این مقاله به معرفی دو اپراتور جالب زبان LINQ، یعنی Cast و OfType و تفاوت بین عملکردآن ها می پردازم
   LINQ
   ۱۲۳۱۶۵
   این مقاله حاوی فایل ضمیمه نمی باشد
   مرتضی صحراگرد
   ۱۳۸۷/۱۱/۳۰
نسخه قابل چاپ نسخه قابل چاپ

تذکر :

قبل از شروع این مقاله باید عرض کنم که با توجه به سیاست های سایت 30sharp، همواره سعی داریم که مقالات را در سطح متوسط و پیشرفته ارائه دهیم تا برای توسعه گران نرم افزار ایرانی، کاملا کاربردی بوده و بتوانند بلافاصله پس از مطالعه مقاله، به بکاربردن آن در برنامه های خود بپردازند. ولی در صورتی که درخواست های کاربران سایت 30sharp به تعداد قابل قبولی برسد، آموزش های پایه ای و مفاهیم اولیه زبان LINQ را در قالب آموزش های ویدئویی ارائه خواهیم نمود تا در سریعترین زمان ممکن، توسعه گرانی که آشنایی کافی با این زبان ندارند، به سطح قابل قبولی برسند.

مقدمه:

اگر تا کنون از تکنولوژی LINQ یا در حقیقت Language Integrated Query در برنامه های خود استفاده نموده باشید، حتما مستحضر می باشید که متد های (یا به عبارت بهتر اپراتور های) زبان LINQ فقط در مورد مجموعه هایی (Collections) قابل استفاده هستند که به طور مستقیم یا غیر مستقیم، اینترفیس IEnumerable<T> را پیاده سازی نموده باشند.

مجموعه های جنریک که برای اولین بار در Dot Net 2.0 معرفی شدند، همگی این اینترفیس را پیاده سازی نموده اند و لذا با خیال راحت می توان از اپراتور های زبان LINQ در مورد آن ها استفاده نمود.

معروفترین این مجموعه ها را در قسمت زیر ملاحظه می نمایید.

  • System.Collections.Generic.List<T>

  • System.Collections.Generic.LinkedList<T>

  • System.Collections.Generic.Queue<T>

  • System.Collections.Generic.Stack<T>

  • System.Collections.Generic.HashSet<T>

  • System.Collections.ObjectModel.Collection<T>

  • System.ComponentModel.BindingList<T>

اما مجموعه هایی نیز وجود دارند که تا قبل از ارائه Dot Net 2.0 بسیار مورد استفاده قرار می گرفتند و به دلیل توسعه و پشتیبانی برنامه های موجود، هم اکنون نیز مورد استفاده قرار می گیرند. در مورد این مجموعه ها، نمی توان به شکل مستقیم از اپراتور های زبان LINQ استفاده نمود. از جمله این مجموعه ها، ArrayList می باشد.

خوشبختانه با استفاده از اپراتور های  Cast و OfType می توان این قابلیت را به این مجموعه ها نیز اضافه نمود.

شروع:

برای شروع، ابتدا با استفاده از یک لیست جنریک، عملیات مورد نظر خود را انجام خواهیم داد و سپس با استفاده از یک ArrayList.

فرض کنید یک لیست جنریک از رشته ها به شکل زیر موجود است و ما می خواهیم رشته هایی که اندازه  آن ها بیشتر از 7 کاراکتر است را نمایش دهیم.

List<string> lst=new List<string>();

lst.Add("Persian");

lst.Add("Develoeprs");

lst.Add("Resource");

lst.Add("30sharp.com");

 این عمل با استفاده از توابع اپراتور به شکل زیر انجام می شود.

var q1 = lst.Where(m => m.Length > 8);

 

//نمایش آیتم های مورد نظر

foreach (var str in q1)

{

    MessageBox.Show(str);

}

 

// خروجی حلقه فوق، دو عبارت زیر می باشند

//      Develoeprs

//      30sharp.com

عمل فوق به شکل زیر نیز قابل انجام می باشد.(با استفاده از Query expression)

var q2 = from m in lst

        where m.Length > 8

        select m;

 

//نمایش آیتم های مورد نظر

foreach (var str in q2)

{

    MessageBox.Show(str);

}

 

// خروجی حلقه فوق، دو عبارت زیر می باشند

//      Develoeprs

//      30sharp.com

حال فرض کنید که لیست جنریک در اختیار نداریم و یک ArrayList داریم که شامل رشته های فوق می باشد.

ArrayList arr = new ArrayList();

arr.Add("Persian");

arr.Add("Develoeprs");

arr.Add("Resource");

arr.Add("30sharp.com");

همانطور که در ابتدای مقاله ذکر شد، به دلیل اینکه ArrayList اینترفیس  IEnumerable<T> را پیاده سازی ننموده است، ما نمی توانیم از اپراتور های زبان LINQ به طور مستقیم در مورد این مجموعه استفاده نماییم.

ابتدا با استفاده از اپراتور Cast این عمل را انجام خواهیم داد.

var q1 = arr.Cast<string>().Where(m => m.Length > 8);

 

//نمایش آیتم های مورد نظر

foreach (var str in q1)

{

    MessageBox.Show(str);

}

 

// خروجی حلقه فوق، دو عبارت زیر می باشند

//      Develoeprs

//      30sharp.com

همانطور که کاملا مشخص می باشد، در قطعه کد بالا، ما قبل از اینکه بتوانیم شرط خود را روی ArrayList اعمال کنیم، نوع داده string را به اپراتور Cast، که یک متد جنریک می باشد، ارسال نموده ایم و در نتیجه فرض بر آن گرفته می شوند که تمامی داده های موجود در این مجموعه از نوع string می باشند و اکنون دیگر می توانیم از اپراتور های موجود در زبان LINQ برای انجام عملیات مورد نظر خود، بر روی این مجموعه استفاده نماییم.

عملیات مورد نظر ما به شکل زیر نیز قابل انجام است. (به کاربرد اپراتور Cast توجه نمایید.)

var q2 = from m in arr.Cast<string>()

        where m.Length > 8

        select m;

 

//نمایش آیتم های مورد نظر

foreach (var str in q2)

{

    MessageBox.Show(str);

}

 

// خروجی حلقه فوق، دو عبارت زیر می باشند

//      Develoeprs

//      30sharp.com

مشکل موجود :

همانطور که می دانید، یکی از مزیت های مجموعه های جنریک این بود که فقط از یک نوع خاص داده می توانستیم در آن ها نگهداری کنیم. به طور مثال در یک لیست جنریک از نوع رشته ای (string)، نمی توانستیم داده هایی از نوع int یا bool نگهداری کنیم و در نتیجه هیمشه مطمئن هستیم که انواع غیر مجاز داده در این مجموعه ها وجود ندارند. ولی در مجموعه های غیر جنریک مانند ArrayList ، سناریو بدین شکل نمی باشد و ما می توانیم تمام انواع داده ها را در آن ها نگهداری کنیم. زیرا این مجموعه داده هایی از نوع object را می تواند نگهداری نماید.

به مثال زیر توجه فرماییید.

ArrayList arr = new ArrayList();

arr.Add("Persian");

arr.Add("Develoeprs");

arr.Add("Resource");

arr.Add("30sharp.com");

arr.Add(100);

همانگونه که مشاهده می نمایید، پنجمین عنصری که ما به ArrayList اضافه نموده ایم یک عدد int می باشد و این بر خلاف سایر آیتم ها است که از نوع رشته می باشند.

اگر از اپراتور Cast در مورد ArrayList بالا استفاده نمایید، هنگام اجرای عملیات، یک خطای استثناء (Exception) به وجود می آید. زیرا ما هنگام استفاده از اپراتور Cast، نوع  string را برای آن مشخص نموده ایم، در صورتی که پنجمین آیتم این مجموعه از نوع int می باشد.

برای رفع این مشکل، به جای اپراتور Cast از اپراتور OfType استفاده می نماییم.

اپراتور OfType، تنها آیتم هایی را از مجموعه ArrayList در محاسبات دخالت می دهد که از نوع رشته (در اینجا رشته است چون ما هنگام استفاده از این اپراتور، نوع string را به آن ارسال نموده ایم) باشند و با سایر انواع داده موجود در ArrayList کاری ندارد.

در شکل زیر نحوه استفاده از اپراتور OfType را ملاحظه می نمایید.

var q1 = arr.OfType<string>().Where(m => m.Length > 8);

 

//نمایش آیتم های مورد نظر

foreach (var str in q1)

{

    MessageBox.Show(str);

}

 

// خروجی حلقه فوق، دو عبارت زیر می باشند

//      Develoeprs

//      30sharp.com

عمل فوق به شکل زیر نیز قابل انجام می باشد.

var q2 = from m in arr.OfType<string>()

        where m.Length > 8

        select m;

 

//نمایش آیتم های مورد نظر

foreach (var str in q2)

{

    MessageBox.Show(str);

}

 

// خروجی حلقه فوق، دو عبارت زیر می باشند

//      Develoeprs

//      30sharp.com

اگر به زبان بسیار ساده بخواهیم تفاورت بین اپراتور های Cast و OfType  را بیان نماییم باید بگوییم که اپراتور Cast فرض می کند که تمام داده های موجود در ArrayList از نوع داده ای می باشد که هنگام تعریف این اپراتور به آن ارسال نموده ایم (در اینجا string) ولی اپراتور OfType فرض می کند که انواع داده دیگری نیز می توانند در این مجموعه وجود داشته باشند و لذا عملیات مورد نظر ما را فقط بر روی آیتم هایی انجام می دهد که از نوع داده ای باشند که هنگام تعریف اپراتور OfType به آن ارسال نموده ایم.

نکته:

با توجه به موارد ذکر شده در این مقاله، پیشنهاد می شود که استفاده از اپراتور OfType را نسبت به اپراتور Cast ترجیح دهید.