با عرض پوزش از اینکه دیر خدمت رسیدم.من سربازی بودم و نتونستم سر بزنم.
خوب توضیح قسمت اول:
انواع مختلفی از آرایه ها موجود اند (یکب بعدی,دو بعدی,دندانه دار,ترکیبی از این انواع و...).در کنار شیء بودن آرایه هاو همچنین ارث بری دینامیکشان ازشیء System.Array باعث میشود
از اجزایی باشند که در زمان اجرا و در CLR بررسی شوند.آندسته از اشیایی که در CLR بررسی میشوند ,اشیاء پیچیده وکاملا دینامیکی هستند.این گونه اشیاء یا اینکه دارای وضعیت نا معلومی درزمان کامپایل هستند(Delegate ها)و یادارای وضعیت پیچیده ای هستند(آرایه ها) و یا هر دو وضعیت را با هم دارا هستند (ژنریک ها).در استفاده از ژنریک ها محدودیتی وجود دارد بنام Special Class.این محدودیت تعامل ژنریک ها را با اشیاء دیگر محدود می کند,و از ترکیب بعضی از اشیاء (که معمولا در CLR بررسی میشوند ودارای وضعیت دینامیک هستند.)با ژنریک ها که معمولا ترکیبی از سه نوع وضعیت بالا را بوجود میآورند,جلوگیری میکنند.مثلا اگر شی ای از کلاس Array را با ژنریکی بکار ببریم وضعیت بسیار پیچیده ای در زمان اجرا بوجود میآید و کامپایل و ایجاد تعامل بدلیل وجود عناصر دینامیک خیلی سخت میباشد.آندسته از اشیاء که دارای یکی از سه وضعیت بالا هستن نمیتوانند در تعامل با ژنریک ها باشند.در نتیجه عجز و عدم توانایی CLR در برخورد با این وضعیت های خاص Special Class بهانه ای میشود که بعضی از اشیاء در تعامل با ژنریک ها از میدان بدر شوند و این نقص را در شیء گرایی دات نت بوجود می آورند.شیئ Object هم این وضعیت را داراست یعنی در لیست Special Classها میباشد .خودت دلیلشو پیدا کن
خدمت شما عرض کنم که Net Framework 1.x بدلیل عدم وجود ژنریک ها شیء گرا نبود و
شیء گرایی Net Framework 2.x هم بدلیل وجود Special Class ها زیر سوال میرود.
اما چرا ژنریک ها عناصر شیء گرایی بودند :
همانطور که شما هم می دانید ژنریک ها تمام قوانین برنامه نویسی شیء گرای
Net Framework 1.x را رعایت میکنند وخصوصیات بسیار خوبی دارند که کارایی , انواع بهتر و مطمئن تری را بوجود میآورند.اما اینها فواید ژنریک ها هستن و تاثیر آنها بر برنامه نویسی شئ گرا اینطور بیان میشود:
فرض کنیم با استفاده از شئ Stack میخواهیم تعدادی عدد را Push کنیم ,سپس یکی از آنها را برداریم کد این مثال اینگونه میباشد:
Stack s = new Stack();
s.Push(10);
s.Push(20);
int a = (int)s.Pop();
همانطور که می بینیم با اینکه به شئ پشته فقط اعدادی را در محدوده int فرستاده ایم ,اما برای برداشتن یک عدد باید تبدیل نوع صریح انجام بدهیم.
در برنامه نویسی شئ گرا این تبدیل نوع دو نوع خطا محسوب میشود:
1)کاربر در کار شئ غیر مستقیم دخالت و نوع بازگشتی را دستکاری کرده
2)کاربر مجبورست خود داده صحیح را بوسیله تبدیل نوع استخراج کند .هر چند که کاربر داده های درست را به شئ پشته فرستاده ولی نوع داده Object تحویل میگیرد.
Encapsulation یا کپسوله سازی دارای سه اصل میباشد.یکی از این اصول اختفای کد نام دارد
اختفای کد نیز دارای اصول زیر است
1)محافظت از شئ در مقابل کاربر:یعنی کاربر در کار شئ دخالت نکند و یا آنرا توسط صفات درونی شئ در وضعیت اشتباه قرار ندهد.
2)محافظت از کاربر در مقابل شئ:یعنی شئ با دریافت داده های درست کاربر را با جزییات درونی خود درگیر نکند و داده های درستی را برگرداند.
اگر به خطوط قرمز و آبی نگاه کنیم متوجه میشویم که خطوط قرمز اصول اختفای کد را نادیده گرفته است.اما اگر همین کد را با کمک ژنریک ها بنویسیم این دو اصل نیز رعایت میشوند.
Stack<int> s = new Stack<int>();
s.Push(10);
s.Push(12);
int a = s.Pop();
در تمامی تبدیل نوع های صریح که از سوی کاربر انجام میشود (بجز مواردیکه کاربر از این کار هدف خاصی دارد) نقض آشکار برنامه نویسی شئ گرا صورت می گیرد.
در نتیجه اگر ژنریک ها نباشند در نهایت آندو اصل نادیده گرفته میشوند و با نادیده گرفتن آن اصول دیگر کپسوله سازی معنایی ندارد.عدم وجود کپسوله سازی در هر زبانی آن زبان را خود بخود غیر شئ گرا میکند.
با این تعاریف باید این نکته را هم در نظر داشت که ژنریک ها در زمینه کپسوله سازی با برنامه نویسی شئ گرا ترکیب میشود ,اما در کنار وراثت و چند شکلی قرار می گیرد و با آنها ترکیب نمی شود .یعنی ژنریک ها در وراثت و چند شکلی فوایدی دارند اما در کپسوله سازی بمنزله پایه هایی عمل میکنند که وجود آنها در هر زبان شیء گرایی اجباریست.
واین یعنی اینکه برنامه نویسی شئ گرا بدون ماهیت وجودی ژنریک ها اعتباری ندارد,کما اینکه نبود ژنریک ها در وراثت و چند شکلی برای آنها مشکل ساز نمیباشد بلکه قدرت را در این عناصر فزونی می بخشد.نهایتا زبانی شئ گرای خالص محسوب میشود که در درون خود از ژنریک ها سود ببرد.