post

10 ميزات لمحرك الألعاب Unity يجب أن تعرفها

السلام عليكم ورحمة الله وبركاته

كيف تُصنع الألعاب؟

إن كنت صرفت جزءاً من وقتك في تجربة لعبة على مر السنوات السابقة، لعله تبادر إلى ذهنك كيف يتم تطوير مثل هذه الألعاب؟ سابقاً كان تطوير الألعاب يتطلب الكثير من الخبرة لأنه كان يعتمد على لغات برمجية مباشرة مثل C و  ++C ، وكان يتم الإستعانة بدوال مهيئة مسبقاً  API ، وهي دوال متخصصة في أمور معينة مثل إظهار الرسوميات والأصوات وغيرها، وأشهر مكتبتين كانتا في ذاك الوقت هما مكتبة DirectX و OpenGL ، وعلى الرغم من أن الـ API كانت تسهل جزء من العمل، إلا أنها كانت تدفع المطور لإستهلاك وقت كبير، دون الولوج إلى فكرة اللعبة نفسها، مما دعت الحاجة إلى تواجدِ شيء أكثر قوة من الـ API نفسها، بحيث يقلل الوقت ويختصر الأمور المكررة.

ما هو محرك الألعاب Game Engine ؟

في تلك الأثناء بادرت بعض الشركات إلى تطوير منظومة برمجية متكاملة، لتستخدمها في كل ألعابها المستقبلية، بعض هذه المنزومات أصبح متاحاً للعلن وبعضها بقي حكراً للشركة نفسها، هذه المنظومة البرمجية نسميها محرك الألعاب Game Engine ، وهو برنامج متكامل تم بناءه خصيصاً لتطوير الألعاب، حيث يوفر مجموعة من الأدوات بدءاً بتصميم المراحل إلى تصدير اللعبة على المنصات المختلفة مثل الـ PC و ال PlayStation وغيرها، ويوفر المحرك أدوات وظيفية لعمليات أساسية أهمها :
– إظهار المجسمات Rendering سواءاً كانت ثنائية البعد 2D أو ثلاثية البعد 3D .
– أدوات لإدارة المشاهد والمراحل وبناءها بشكل يساعد المصممين على ذلك،
– أدوات تسهل عملية التطوير والبرمجة وإرفاقها إلى المجسمات المختلفة.
– دوال للتحكم في فيزيائية الأجسام وتصادمها.
– أدوات لتشغيل الأصوات وتأثيرها في الفضاء ثلاثي الأبعاد.
– أدوات للتحريك الحر وتحريك أنظمة متكاملة مثل الشخصيات والمجسمات الصلبة.
– أدوات لإدارة الذاكرة وتنظيمها ومنع أي إستهلاك زائد قد يؤدي باللعبة إلى التوقف.
– أدوات للذكاء الإصطناعي وإيجاد أفضل طريق لسلوك المجسمات بناءاً على طبيعتها.
– أدوات للعب الجماعي Networking وكيفية ربط اللاعبين ببعضهم مباشرة.
– أدوات تسهل عملية التصدير إلى منصات الألعاب سواءاً للحواسيب أو الموبايل أو ال Consoles المختلفة.
كل هذه الجزئيات وغيرها يوفرها محرك الألعاب، ليجعل المطور يستثمر وقته بشكل أفضل للتركيز على فكرة لعبته.

ما هو محرك Unity ؟

إن كنت قريباً من مطوري الألعاب أو من بعض شركات الألعاب لعلك سمعت بإسم Unity Game Engine، حيث أن محرك الألعاب Unity يعتبر من أقوى وأفضل المحركات حالياً، لإمتلاكه العديد من الخصائص التي تؤهله لذلك، فضلاً عن سهولة تعلم أساسيات المحرك، التي  تأخذ الوقت القليل مقارنة بمحركات الألعاب الأخرى، مما يجعلك مؤهلاً للإنتقال والتركيز على مضون فكرة لعبتك، تعالو معنا لنتعرف عن قرب على أهم خصائصه وميزاته:

1 – محرك مرن وقابل للتأقلم مع متطلباتك :

محرك الألعاب Unity متوفر لنظام Windows  ونظام Mac ، ويتميز بواجهة رسومية صديقة للمستخدم، سلسة وقابلة للتغيير إلى الشكل الذي يناسب المطور، والمحرك يدعم تطوير الألعاب ثنائية البعد 2D وثلاثية البعد 3D ويتيح الأدوات التي يحتاجها كل نوع على حدى، ويحتوي على أدوات للذكاء الإصطناعي مثل إختيار أفضل وأقرب طريق مع وجود عوائق، حيث يتيح أدوات مخصصة يمكنك إدراجها في مشهدك لتبدء بالتنفيذ مع التغيير البسيط على إعداداتها، والمحرك يتيح أيضاً أدوات خاصة لبناء الواجهات UI المختصرة من User Interface والتي تبقى على شاشة اللاعب بغض النظر عن حركة المجسمات الداخلية، فضلاً عن إحتياجك لها لبناءقوائم في ألعابك مثل الـ Main Menu وغيرها. والمحرك يوفر الحسابات الفيزيائية فهو يعتمد على محرك Box2D في حالة كنت تريد عمل لعبة ثنائية البعد أو محرك NVIDIA PhysX في حال كنت تريد عمل لعبة ثلاثية البعد، وهذين المحركين هما الرائدين في هذا المجال، ليس هذا فحسب، بل يتيح لك المحرك القدرة على إضافة أدوات خارجية تقوم أنت ببناءها أو تحضرها من متجر Unity Asset Store أو من أي مكان آخر يناسبك.

2 – أدوات للمصممين والفنانين :

من أكبر الأخطاء التي يقع بها البعض، إعتقادهم أن محرك الألعاب موجه ومقتصر على المبرمجين فقط، والحقيقة أن محرك الألعاب Unity موجه للمبرمجين وللرسامين وللفنانين ولأعضاء فريقك الآخرين، فهو يقدم أدوات لتصميم ورسم المراحل التي يحتاجها الـ Level Designer فهناك أدوات 2D و 3D ، وهناك أدوات للإضاءة Lighting Tools يحتاجها إختصاصي الإضاءة، وهناك أدوات للصوت Audio System يحتاجها فني الأصوات، وهناك أدوات للقصاصات Sprite management Tools يمكن للمصمم إستخدامها، وهناك أدوات لأنظمة الجزئيات Particle Effects تشبع رغبة مختص ال Visual Effects ، وهناك أدوات للحركة Dopesheet Animation System تساعد الـ Animator على إنهاء حركته بأكمل وجه، وهناك أدوات فنية أخرى كفلاتر الكاميرا Post Processing Effects وأدوات أخرى.

3 – عارض آني للرسوميات Realtime Graphics Rendering :

ما تراه داخل محرك اللعبة هو ما سيكون ظاهر للاعب لاحقاً، وهذه ميزة كبيرة جداً تتيح لك إطلاق العنان لمختيلتك ولإبداعاتك، فيمكن تصميم ساحل جميل مع أشعة الشمس الرائعة أو حتى أخذ اللاعب إلى سباقات السيارات داخل المدن ليلاً والتمتع بإنعكاسات الإضاءات في كل مكان، فمحرك الألعاب Unity يمتلك عارض آني للرسوميات Real time Rendering تُمكنك من إنتاج إضاءة واقعية Real-Time Global Illumination  مع فيزيائية للمواد حقيقية Physically Based Rendering من إنعكاس وإنكسار لمختلف المواد الموجودة في الواقع الحقيقي. ليس هذا فحسب، بل إن المحرك لأنه يدعم كل المنصات فهو قريب من دوال الرسوميات الأساسية low level graphics API لكل منصة، هذا يجعله قادراً على أخذ ميزات كروت الشاشة الحديثة التي يتم تطويرها بشكل دوري فهو يدعم ال API التالية : Vulkan و iOS Metal و DirectX12 و nVidia VRWorks و AMD LiquidVR .

4 – مشروع واحد وتصدير لعدة منصات :

وهذه تعتبر من أكثر الميزات التي تجعل العديد من المطورين يتوجهون نحو محرك Unity ، فما عليك سوى أن تقوم ببناء لعبتك لمنصة إبتدائية وبعد الإنتهاء منها يمكنك بضغطات قليلة وبتعديلات جداً بسيطة تصديرها إلى منصة أخرى، فالمحرك قادر على تصدير لعبتك إلى أكثر من 25 منصة فيمكنك نشر لعبتك على أجهزة ال Desktop وأجهزة الـ mobile  و أجهزة الـ Consoles و الويب والتلفاز وأجهزة ال AR و ال VR وهنا إستعراض للمنصات الحالية والقائمة تزداد بين الحين والآخر. بالإضافة إلى أن هناك العديد من الشركات التي تستخدمه في مشاريعها مثل شركة Ubisoft و لمخرجين من Hollywood وصولة إلى وكالة الفضاء NASA . وأيضاً يعتبر من أكثر المحركات إستخداماً في تطوير تطبيقات وألعاب الواقع الإفتراضي والواقع المعزز.

5 – متجر لكل مستلزمات مشروعك :

أيضاً من الميزات التي لا يمكن تجاهلها هو إمتلاكه لمتجر يحتوي على كل ما يمكن أن يلزمك لتطوير لعبتك، وهو ما يطلق عليه إسم Unity Asset Store ، فهو يحتوي على إضافات لنفس المحرك تسهل وتزيد من الإنتاجية ، ويوفر لك الكثير من المجسمات ثلاثية الأبعاد ، والصور ثنائية الأبعاد ، والأصوات والموسيقى، وأسطر برمجية تقوم بوظائف معينة ، بل حتى يوفر لك مشاريع كاملة يمكنك إعادة إستخدامها بما يتناسب وطبيعة لعبتك. ونذكر هنا أن كل هذه المصادر متاحة على المتجر إما مجانية أو مقابل سعر يضعه المطور، فمن يقوم بوضع هذه المصادر ليس فقط الشركة نفسها، بل يتجاوز إلى كل المطورين والرسامين والمصممين ومهندسي الصوت وغير ذلك، وأنا شخصياً لي تجربة فريدة مع هذا المتجر وهو يعود لي بدخل شهري مناسب جداً.

6 – شبكة لاعبين Networking :

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

7 – تطوير تشاركي للفريق في نفس الوقت :

من أكثر الأمور التي تؤرق فرق العمل هو كيفية تجميعها وكيفية إرسال المهام المنجزة وكيفية ربطها في مكان واحد يستطيع الكل مشاهدة النتيجة النهائية للعمل من غير نسخ كثيرة ومن غير ضياع لملفات هامة، هذا بالضبط ما يوفره محرك الألعاب Unity من خلال خدمة Unity Teams ، فبهذه الميزة يمكنك الآن العمل مع صديقك أحمد على نفس المشروع حيث يتم رفعه بشكل Online على خادم شركة Unity وتقوم بالعمل على نسخة محلية منه على جهازك، فإن قمت بالتعديل على ملف أو مجسم معين، كل ما عليك فعله هو أن تقوم بتزامن هذا الملف إلى الخادم ليأتي تنبيه إلى أحمد أن هناك نسخة جديدة من هذا الملف وتستطيع تحميلها لترى ما الجديد فيها، ليس هذا فحسب، بل يقوم الخادم بأخذ نسخة إحتياطية من الملف القديم في حال لزمك الرجوع له في المستقبل، فالمحرك يقوم فعلياً بخدمتين، خدمة تسهيل العمل بتزامن الملفات وخدمة حفظ أرشيف للملفات القديمة أو ما يعرف بال Source Control ، مع التنويه أن هذه الخدمة ليست مجانية وهناك مبلغ شهري بسيط تدفعه للحصول عليها.

8 – منصة إجتماعية لعرض أعمالك :

ومن الخدمات والميزات التي تقدمها شركة Unity أيضاً هي منصة Unity Connect الإجتماعية الخاصة بمطوري الألعاب ، وهذه المنصة مشابهة للمنصات الفنية مثل Behance لشركة Adobe وغيرها من المنصات التي تتيح لك عرض أعمالك ومشاريعك التي أنهيتها أو التي تقوم بالعمل عليها حالياً، ليس هذا فحسب ، بل من خلال منصة Unity Connect يمكنك التعرف على خبراء في هذا المجال وبإمكانك البحث عن عمل أو حتى البحث عن شخص يساعدك في مشروعك سواءاً بمقابل مادي أو بطريقة تشاركية يتم الإتفاق عليها بينك وبينه. وهذه المنصة لها العديد من الفوائد ويجب على كل مطور يعمل على Unity أن يشترك فيها لما تعود عليه بالنفع المرحلي أو الدائم.

9 – تغذية راجعة مباشرة من اللاعبين :

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

10 – أكثر من خيار للربح :

هناك العديد من المطورين يقومون بإنتاج ألعاب لأنها متعة بحد ذاتها، ولكن الشريحة الأكبر توجه الألعاب لتكون طريقة ربح، فأرباح الألعاب في السنوات الأخيرة أصبحت هائلة وتفوق مجالات عديدة منها صناعة الأفلام، لذلك محرك الألعاب Unity يقدم لك خيارين تستطيع من خلالهما إستثمار لعبتك لتعود بمقابل مادي، أولهما هو إمكانية وضع ميزات يمكن شراءها بمقابل مالي في داخل اللعبة وهي ما تعرف بالإختصار IAP من الإختصار In App Purchase ، وثانيهما هو إضافة إعلانات Ads داخل اللعبة من نفس شركة Unity حيث تقوم بإعطاءك مبلغ معين على عدد مشاهدات الإعلان، أو بإمكانك إستخدام مزود إعلانات آخر مثل Admob من شركة Google وغيرها من المزودات الربحية.

الخلاصة :

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

post

#19 مواضيع متقدمة عن Classes – البرمجة بواسطة #C

رمز فتح مرحلة هذا الدرس في تطبيق طورني : MRE

تَعلُمُ البرمجةِ للمبتدئينَ كلياً بواسطةِ #C –  مواضيع متقدمة حول الفئات Classes

مواضيع متقدمة حول الفئات Classes :

ما هو الـ Garbage Collector ، و ما هي دلالات كلمة  new التس نستخدمها عند الاشتقاق من الكلاس الرئيسي ، ما هي الـ Static ، و ما هو الـ Constructer الدالة التي تقوم بتنفيذ أسطر برمجية عند الاستنساخ من كلاس رئيسي ؟

هذا كله سنتعرف عليه في هذا الدرس بعد الفاصل إن شاء الله .

 

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

بسم الله الرحمن الرحيم ، في الدرس الماضي تحدثنا عن مدخل إلى البرمجة كائنية التوجه OOP و التي هي اختصار لـ Object Oriented Programming ، و تعلمنا كيفية بناء Class ، و التي  أصبحنا نعلم أنه يمكن ترجمة الـ Class إلى العربية بكلمة ” الفئة ” ، و تكلمنا كيف يمكنك بناء فئات أو Classes تحوي معلومات مشتركة ، و رأينا كيف يمكننا تعريف الـ Property  و رأينا كيف يمكننا استنساخ Object من هذا الـ Class

في هذا الدرس سنتكلم إن شاء الله عن أمور و تطبيقات إضافية للـ Classes و الـ Method نفسها ، و سنتكلم عن مفهوم الـ Object نفسه ، فما هو مفهوم الـ Object عندما نقوم باشتقاقه من الـ  Class ، و كيف يتم تخزينه و استدعائه ، و ماهي حلقة الوصل بينه و بين الذاكرة ، سيتم مناقشة هذا في القسم الأول من الدرس ، و سنراجع معاً ما هو دور الـ Dot Net Runtime في عملية إدارة الذاكرة .

 

تكلمنا في البداية أن الـ Dot Net له أقسام معينة و هو مسؤول عن تحويل أمور معينة و تعرفنا على Common Language Runtime و اختصارها CLR ، حيث سنأخذ فكرةً عنها ، و كيف ستساعدنا هذه الأمور في انتاج برامج قوية قادرة على إدارة الـ Data  ، و قادرة على إدارة عمل البرنامج بشكل افضل .

و سنتكلم أيضاً عن شيء يسمّى Constructer  ؛ و هو Method خاصة يتم استدعاؤها عندما يتم استنساخ Object من الـ Class ، و سنتكلم أيضاً عن معنى كلمة Static ، و التي رافقتنا من أول درس إلى هذا الدرس .

 

كالعادة نقوم بإنشاء مشروع جديد بلغة c# من النوع Console App

في الدرس الماضي تكلمنا عن المكان المناسب لتعريف الـ Class ، حيث قلنا أنه يجب أن يكون موازياً للـ Class الرئيسي ، في المنطقة الواقعة داخل الحافظة الرئيسية namespace  ؛ و التي تحتوي على مجموعة من الكلاسات .

 

في البداية هناك قضية أودُّ التنويه لها ، و هي إمكانية كتابة Class ضمن كلاس آخر ، أو ما يعرف بالـ Nested Class ، لكننا لن نتعمق في هذا الموضوع ، و سنتعلم الـ Class بمفهومه البسيط ، و الذي يمكن استخدامه في أي مكان .

إذا لكتابة Class جديد نذهب لأي منطقة موازية لأي كلاس آخر ، و يمكن كتابة الـ Class فوق الكلاس الرئيسي أو تحته ، فلا مشكلة في هذه النقطة ، إذا سننتقل إلى السطر رقم 15 ، و أقوم بكتابة نفس الـ Class الذي تعاملنا معه في الدرس الماضي .

لاحظوا أن هذا الـ Class المسمّى Car يحتوي على 4 خصائص ، كل منها لديه نوع خاص ، فالشركة المصنعة لديها النوع string و سنة التصنيع من النوع int .

اشتقاق Object من Class معين :

و لاشتقاق Object من هذا الـ Class تعرفنا أنه يمكننا كتابة اسم الـ Class الرئيسي أولاً ، ثم نقوم بتعريف متغير جديد myCar على سبيل المثال ، ثم وضع إشارة المساواة ، ثم new ثم اسم الكلاس مرة أخرى ، مع وضع اقواس () و الفاصلة المنقوطة ، حيث قمنا هكذا بجعل هذا الـ Object مستنسخاً من الـ Class الذي اسمه Car ؛ لاحظوا في هذه الجملة قمنا بتعريف متغير نستطيع أن نقول عنه أنه Object من النوع Car ، و لاحظوا أنه عندما قمت بوضع كلمة new فهناك عمليات موجودة خلف هذه الكلمة .

 

ما معنى كلمة new ؟

عندما تقوم بعملية استنساخ أو بناء مجسم جديد ، فأنت فعلياً قمت بربط هذا المجسم و معلوماته بمكان معين في الذاكرة ، Address  معين في الـ Memory ، و هذا المكان في البداية هو مكان فارغ عندما قمنا بكتابة Car myCar ، و لكن عندما قمنا بكتابة new Car قمت بإضافة المعلومات الأساسية التي يتكون منها هذا الكائن ، فعندنا في البداية كائن قمنا بتعريفه فارغاً و لكن عندما قمنا بعملية ربطه بكلمة new قام فعلياً بعملية انشاءه و تهيئته بالشكل الذي قمنا بكتابته في الـ Class ، و سنتعرف بعد قليل على ميزة خاصة بعملية الـ new Car الموجودة هنا .

يمكن أيضا تشبيه هذا الموضوع بالبالون ، حيث نفترض بالون معين يطير في الهواء ؛ هذا البالون له خيط ، هذا الخيط هو عبارة عن الـ myCar ، و هو اسم المتغير  ، أما المعلومات الموجودة به فهي موجودة على البالون ، فالمتغير يدل على المنطقة في الذاكرة التي تحتوي المعلومات الكاملة .

 

القضية التي نودُّ شرحها هنا أنه بإمكاننا كما تعرفنا في الدرس السابق ، بإمكاننا إضافة المعلومات الموجودة بداخله ، حيث نضيف معلومات اللون و الخصائص السابقة ،

يمكننا أيضاً إضافة Object آخر من نفس النوع Car و جعله يشير إلى نفس المكان الموجود في الذاكرة ، بمعنى … سنقوم بإضافة متغير جديد باسم myOtherCar ، و لاحظوا أنني في هذه الجملة قمت بتعريف Object لكنه فارغ ، لا يشير إلى مكان في الذاكرة ، أو ليس له محتويات يشير إليها ، فإن قلت له في السطر التالي ، myOtherCar = myCar ، ففعلياً في هذا السطر جعلت الـ Object يشير إلى المكان الذي يشير إليه myCar

نعود لمفهوم البالون لتوضيح الصورة أكثر .

لدينا البالون الذي اتفقنا سابقاً أن له خيطاً و اعتبرناه myCar ، بالجملة التي كتبناها قمنا بعمل خيط آخر ، و الذي هو myOtherCar و الخيطين يشيران إلى نفس البالون ، و لاحظوا أنني لم أقم بإسناد أي قيمة للمتغير ، بل جعلته مساوياً للـ Object السابق .

بمعنى أنني إذا قمت بعمل طباعة الجملة التالية ، فعندها سيقوم بطباعة Black ، على الرغم من أنني قمت بطباعة myOtherCar  و ليس myCar ، إذا فعليا في المتغير myOtherCar قمت بالإشارة إلى نفس البالون الذي يحمله الـ myCar و لتتأكدوا أكثر أن الاثنان مرتبطان بنفس المنطقة في الذاكرة ، سأقول له
;”myOtherCar .color = “Red
أنا فعلياً هنا قمت بتغيير اللون لـ myOtherCar و ليس myCar ، و سأقوم مباشرة بطباعة myCar.color
و للتوضيح باختصار : انا قمت بتعريف متغير myCar و قمت بوضع اللون الأسود له ، ثم قمت بتعريف Object آخر من النوع Car و قمت بإسناد موقع الـ myCar إلى myOtherCar ، و قمت بتغيير myOtherCar.color ،و سأقوم بطباعة الـ myCar الأولى ، عند التشغيل سيظهر Red المعدلة و ليس Black ، لأنه كما ذكرنا أنه عبارة عن مكان موجود في الذاكرة و هناك أكثر من خيط يشير له ، فأي تعديل على أحدهما يؤثر على الآخر ، فـ myCar و myOtherCar هما عبارة عن خيوط للمكان المحجوز في الذاكرة نفسه .

 

ماذا لو أردت أن أقطع هذا الخيط ، بمعنى أريد فصل myOtherCar عن المكان الذي قمت بتعريفه في الأعلى . بمعنى أن تنفصل myOtherCar عن myCar ، فأنا أريد جعلها تشير إلى مكان آخر في الذاكرة ، فعلياً في السطر 17 أنت تعرف خيطاً فقط لا يشير إلى شيء ، و لا يوجد معلومات به ، و لا نعرف كيف سيكون و ما هي محتوياته ، لذلك يوجد جملة myOtherCar = null هذه القيمة null فعلياً فارغة ، و بذلك في السطر 20 قلت له أن يقوم بفصل myOtherCar عن أي شيء آخر ، و اجعله فارغاً لا يحوي أي شيء ، و بذلك ، و بدءاً من هذا السطر لو قمت بعملية طباعة أي معلومة من معلومات  myOtherCar فسنلاحظ أنه سيظهر مشكلة و خطأ برمجي ، و هو : myOtherCar was null  أي أنه فارغ !! و لا أعرف ما هو الـ color الذي تريده ، و لذلك لا اعرف كيفية طباعة هذه الجملة ، و بالتالي يظهر الخطأ .

إذاُ .. فعليا في السطر 20 قمت بقطع الحبل الخاص بـ myOtherCar الذي كان يربطه بالبالون ؛ و عند هذا السطر ، فقط myCar هو الذي يحتوي الوصلة للبالون .

 

إذا قمت بعد ذلك بقص الخيط الثاني  و ذلك بجعل myCar  تساوي null أيضاً ، و لاحظوا أنني هنا بعد تعريف الـ  Object و اضافته أن هناك بالون معين و يحتوي على المعلومات القيمة التي أريدها . و بعد السطرين 20 و 21 قمت بقطع الشريطين ، و طار البالون في الهواء و المعلومات فعلياً ذهبت إلى الأعلى و انفجرت !!

إذاً القضية التي أريد أن اوضحها لكم أن في هذه الخطوات هي فعلياً عملية ربط Object معين بموقع ، و عندما تقوم بفصله ، أو عندما يصل إلى نهاية الـ Block الذ تم تعريفه داخله فإنه فعلياً يصبح null  أي فارغاً بغض النظر عن السطرين 20 و 21 .

 

هنا يأتي دور Dot Net Runtime فماذا يفعل ؟؟

هناك معلومات قيمة و معلومات كثيرة ، فنحن الآن نتكلم عن كلمتين أو خمس حروف و هكذا ، و لكن ماذا عن المشاريع الكبيرة ، عندنا كم هائل من الـ  Data و هذه البيانات إذا بقيت في الذاكرة و لم يتم التحكم بها ، فسيكون هناك مشاكل كبيرة نحن بغنى عنها ، و هنا يأتي دور الـ Dot Net Runtime  و الذي قلنا سابقاً أن اختصاره هو CLR سيقوم بالتالي :

ستذهب و تبحث في جميع الأكواد التي قمنا بكتابتها في هذا البرنامج ، و ستجد أن هناك بالون فارغ لا يوجد أي وصلة له ، و تقوم بالبحث إن كان هناك خيوط مرتبطة بهذا البالون أم لا ، و فعلياً لن تجد أي وصلة له ، و تقول : ” أنت يا بالون خارج  التغطية و لا أريدك ، سأقوم بتهيئة مكانك ، قم باستخدامه لمتغير آخر استفيد منه خلال البرنامج ”

إذا هذا الموضوع الذي يقوم بحذف و إدارة الذاكرة شيء يسمى Garbage Collector ، هو شيء خاص بـ CLR ، و يقوم بالبحث عن المناطق أو الـ Object  التي تم فصل الارتباط بها ، و يقوم بتهيئتها لاستخدامها بشيء آخر ، هذا المصطلح يجب أن تكونوا على اطلاع عليه ، و نحن عندما نقول أن لغة السي شارب هي لغة managed  يعني أنه يوجد شيء وسيط بينك و بين الآلة يقوم بإدارة أمور معينة أنت في غنى عنها ، و لكن لاحظوا أننا عندما نقول عن لغة السي و السي بلس بلس هي لغة unmanaged  ، فإنك عندما تقوم بالتعامل مع هذه اللغات فأنت مضطر لمتابعة المتغيرات و الذاكرة و مواضيع أخرى ، فأنت مجبر أن تقوم يدوياً بعمل تفرغ لكل Object  قمت بالانتهاء منه ، كي لا تحدث مشاكل في الذاكرة و حجم البرامج ، و مشاكل كبيرة أنت في غنىً عنها .

لماذا اخترنا السي شارب ؟؟
لأنها لغة managed ، حيث توفر لنا إمكانيات و أدوات نحن في غنىً عن الغوص في تفاصيلها ، فنحن نريد أن نركز على فكرة التطبيق الذي نريد عمله

 

الآن في السطر رقم 13 عند تعريف Object  جديد قمت باستخدام قوسي الدالة () ، الحقيقة هنا يتم استدعاء  Method داخل الكلاس حتى و إن لم تقم بكتابتها و تعريفها ، ألا و هي دالة الـ Constructer  ، و هي دالة يتم استدعاؤها عندما تقوم بعمل initialize  للـ Object ، بمعنى أنه عندما تقوم بعمل فتح و اغلاق قوس يتم تنفيذ شيء معين ، و فعلياً هنا لأننا لم نقم بكتابة شيء ، هو قام بمناداته ، و لكنه ضمنياً فارغ .

لكي نتعامل مع هذا الموضوع و نتعرف عليه أكثر ، سنقوم الآن بالتعرف على كيفية كتابة الـ constructer  .

شكلها كالتالي :

()public Car

{
}

و اسمها طبق الأصل مع اسم الكلاس ..
هذه الأسطر من 29 إلى 32 ضمنياً موجودة ، و لكنها فارغة ، طالما قمت بكتابتها ، فالأولوية لما قمت بكتابته ، سأقوم بعمل التالي :

سأقول له عندما تقوم بعمل Object  جديد ضع الشركة مثلا Nissan  و سأقوم بالرجوع إلى الأسطر في الأسفل و اجعلها جمل ملاحظات .

أنا فعلياً قمت بتعريف الـ Object ، و لكن لم أقم بإسناد أي قيمة ، فقط قم بطباعة الـ Make  و عندما أقوم بتنفيذ التطبيق سيقوم بطباعة كلمة Nissan  ؛ من أين أتت هذه الكلمة !!!!

هذه الكلمة أتت من الـ Constructer    و هو كما قلت يتم استدعاؤه ضمنياً عندما تقوم بعملية استنساخ Object  جديد ،

هنا أيضاً مفهوم آخر ذكرناه في الMethods و سنعيده مرة أخرى  ، ألا و هو الـ Overload ، و هو إمكانية كتابة نفس الـ Method بنفس الاسم ، لكن مع اختلاف عدد الـ Parameter الموجود بداخلها ، لاحظوا أننا تكلمنا أنه داخل الـ Method بإمكانك إضافة  Parameter معينة  يتم اسنادها من خارج الدالة و يتم التعامل معها من داخل الدالة .

سنقوم بإضافة دالة جديدة و هي عبارة عن public Car و لكن سنقوم بإضافة Parameter  من خارج الدالة ، و تسمى هذه العملية Overload ، فسأقول له مثلاً string make  و string model  و int year و string color  ، و لاحظوا أن الكلمة make  تختلف تماما عن الكلمة Make لأننا تكلمنا أن لغة سي شارب هي لغة Case sensitive  فالحرف الصغير يختلف عن الكبير ، إذا في الـ overload هذه هنا سأقوم بعمل التالي ، حيث أنني في السطر رقم 13 ثمت بتعريف Object  جديد و القوسين فارغين ، فعليا قام باستدعاء الدالة التي قمنا بكتابتها ، و لكن أريد منه أن يقوم في عملية الـ Initialization أن أسند إليه قيماً و يقوم مباشرة بوضعها داخل كيان الـ Object  للتعامل معها لاحقاً .

فمثلاً سأقول له كالتالي :

الـ Make ذات الحرف الكبير اجعلها الـ make ذات الحرف الصغير ،  و التي أرسلتها من خارج الدالة

و كذلك بالنسبة للـ Model & Year & Color ، نعود للأعلى في السطر 13 ، بمجرد فتح القوس الأول يقوم بإظهار خيارات ، و بالضغط على الأسهم الظاهرة ، ستلاحظ أنه يوجد أكثر من Method يمكن استدعاؤها ، و هنا الأولى لا تحتاج أي Parameter و التي استخدمناها في السطر السابق ، و لكن هنا أريد استخدام الثانية ، حيث أريد اسناد الشركة و الموديل و السنة و اللون في نفس السطر ، فسأقول له  BMW مثلا , و كذلك الموديل و السنة و اللون ، إذا قمت بإنشاء Object جديد و قمت باستدعاء دالة البناء التي تحتوي على Parameter .

إذا عندما أقوم بعمل طباعة لنوع الشركة ، لن يقوم بإعادة اسناد Nissan بل سيقوم بطباعة BMW لأني قمت بإسنادها في بداية انشاء التطبيق  .

فهذا هو مفهوم الـ Constructer ، و هو مميز جداً   ، و استخدامه مفيد جداً في حالات كثيرة .

 

كلمة Static :

القسم الرابع من درسنا هو كلمة Static  ، لاحظوا أننا من أول تطبيق و حتى الآن ، كانت ترافقنا كلمة static الموجودة في الـ voidMain ، فقد تكلمنا عن int و string و void و تحدثنا عن الـ Class و كيف يمكننا استخدامه  و تحدثنا عن كلمةnew و تعلمنا كيف يمكن استخدامها  .

لطن ما معنى كلمة static ، و لماذا ترافقنا دائماً ، و لماذا في درس الدوال عندما قمنا بإضافة دالة ، وضعناها أيضاً من النوع Static كي نتمكن من استخدامها داخل الـ  voidMain ؟

الحقيقة أن كلمة static هي شيء يكون standard في كل الكلاس ، فكلمة Make و Model و Year و Color هي لا تتبع للكلاس ،هذه تتبع للـ Object المستنسخ من الكلاس ، فإن قمت بكتابة Car و بعدها نقطة ، فلن أجد الـ property السابقة ، لماذا ؟؟

لأن الـ Property الموجودة هنا تكون تابعة للـ Object الذي يأتي بعد عملية الاستنساخ ، فهنا عندما قمت باستنساخ Object جديد و وضعت myCar و النقطة ، حصلت على كل الـ Property الموجودة فيه ، و لدي أيضاً دوال ستكون متاحة هنا ، لماذا؟

لأنها ليست من النوع static

أما عندما أقوم بتعريف متغير جديد من النوع static ، لاحظوا أنني قمت بتعريف Property جديدة و لكنها من النوع static ، فهي تعني أن هذه الـ Property يمكن استدعاؤها من الكلاس نفسه ، بذكر اسم الكلاس قم ارفاقه مباشرة و ارفاق اسم الـ static ، إذاً عندما أكتب Car و هي اسم الكلاس بالحرف الكبير ، و اضع النقطة ، مباشرة أصبح لدي Property يمكن استخدامها على مستوى الـ Class .

 

دعونا الآن نتعامل مع الكلمة static بشكل أكبر .

لاحظوا هنا في داخل الكلاس ، وضعت أنه عند تعريف متغير جديد سيقوم بتغيير الـ Make ، مبدئياً سأقوم بعملها جملة ملاحظة ، و سأضع ، عندما يتم انشاء Object جديد ، قم بزيادة الـ Count برقم 1 ، فإذا قمت بطباعة Car.Count ، فعملية الزيادة لا تتم في الـ Constructer الذي يقوم بإعطاء parameter ، فأنا عندما قمت بإنشاء مجسم جديد ، لم أقم باستخدام هذا الـ Constructer ، بل قمت باستخدام الثاني ، و الذي يقوم بإعطاء وParameter ، ففعلياً هنا لا يوجد زيادة ، فبالتالي تظهر القيمة 0 ، لذلك سنقوم بعمل جملة الزيادة جملة ملاحظة و وضعها في الـ  Constructer الثاني ، و نجعل السيارة الثانية فارغة تستدعي الـ Constructer الأول ، و بذلك تكون السيارة الأولى و الثالثة تستدعي الـ Constructer الثاني ، أما الثالثة ، فتقوم باستدعاء الأول ، و عندها في كل Constructer يتم زيادة القيمة بواحد ، و لدي 3 سيارات ، فعندما أقوم بطباعة الـ Count يجب أن يظهر الرقم 3 .

 

موضوع الـ static  ليس حصرياً على الـ Property بل يمكن استخدامه كذلك في الـ Method .

لاحظواً أننا طول الوقت ، و من أول سطر لم نقم باستنساخ مجسم من الـ Console Class ، لم نقل له أعطني مجسم جديد و اريد استخدام هذه الدالة .

لاحظوا أن الـ Method ذات الاسم WriteLine تابعة مباشرة لاسم الكلاس ، و ليست تابعة لـ Object يتم اشتقاقه من الكلاس .

ايضاً مر معنا في درس التاريخ و الوقت أننا قمنا بالتعامل مع هذه الـ Property المسماة Now ، و هي لا تحتاج لعملي اشتقاق من الـ Data Type المسماة DateTime ، فقد حصلت عليها مباشرة من خلال النقطة ، لأن هذه الProperty عبارة عن static .

أيضاً لو لاحظتم في درس المصفوفات ، حيث تعاملنا مع دالة Reverse ، و هي ايضاً لا تحتاج لعملية اشتقاق من الكلاس Array .

إذا بالمثل سأقوم بإنشاء Method جديدة ، هذه الدالة من النوع static  أي أنها تابعة للكلاس بشكل كامل ، و سأقوم باستدعائها بالكلاس الرئيسي ، و حيث أن هذه الدالة تقوم بطباعة Count
و لو قمت بتنفيذ التطبيق سيقوم بطباعة عدد السيارات التي قمت بإنشائها من هذا الكلاس .

 

مصطلحات الدرس :

Garbage Collector :

Static :

Constructer :

Object Oriented Programming (OOP) :

Property   :

Object :

Class :

Dot Net Runtime :

Common Language Runtime (CLR) :

namespace   :

Nested Class :

null   :

managed   :

unmanaged  :

initialize   :

Initialization :

Parameter :

Reverse :

Count :

Public  :

الأسطر البرمجية التي قمنا بتنفيذها في هذا الدرس

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObjectLifeTime
{
    class Program
    {
        static void Main(string[] args)
        {
            //Car myCar = new Car();
            Car myCar = new Car("BMW","Z",1990,"Yellow");
            Car myCar2 = new Car();
            Car myCar3 = new Car("BMW","Z",1990,"Yellow");
            
            Car.PrintCount();
            //myCar.Color = "Black";

            //Car myOtherCar;
            //myOtherCar = myCar;
            //myOtherCar.Color = "Red";
            //myOtherCar = null;
            //myCar = null;
            
            //Console.WriteLine("{0}", Car.Count);
            Console.ReadLine();
            
        }
    }
    class Car
    {
        public Car()
        {
            //Make = "Nissan";
            Count++;
        }
        public Car(string make,string model,int year,string color)
        {
            Make = make;
            Model = model;
            Year = year;
            Color = color;
            Count++;
        }

        public static void PrintCount()
        {
            Console.WriteLine("{0}", Count);
        }

        public static int Count { get; set; }
        public string Make { get; set; }
        public string Model { get; set; }
        public int Year { get; set; }
        public string Color { get; set; }
    }
}

post

البرمجة كائنية التوجه OOP – الجزء الأول

البرمجة كائنية التوجه OOP :

السلام عليكم ورحمة الله وبركاته، عندما تم تطوير البرمجة كائنية التوجه Object Oriented Programming المعروفة بالإختصار OOP أحدثت ثورة كبيرة في علم البرمجة، فلقد قامت بحل العديد من الإشكاليات والمعضلات التي كانت تؤرق المطورين أنفسهم، سنأخذكم في جولة سريعة نشرح فيها أهم المبادئ للبرمجة كائنية التوجه ومن ثم نتطرق إلى كيفية إستخدامها داخل لغة #C مباشرة، فمن أهم مبادئها :

التغليف (Encapsulation ):

وتعني ببساطة منع الوصول إلى المتغيرات الموجودة داخل الكلاس بشكلٍ مباشر، والسماح بتعديلها أو استرجاعها من خلال دوال مخصصة لذلك، وتبرز أهمية التغليف في قدرتنا على وضع قواعد معينة للتعامل مع المتغيرات، مثلا لنفرض ان هناك متغير لتخزين عمر الشخص، لو أتحنا الوصول المباشر لهذا المتغير سنفقد أي تحكم بالقيمة التي سيدخلها الشخص الذي يستخدم هذه الفئة Class (مبرمج آخر)، ولربما لن يكون لديه معرفة كافية عن طريقة عمل هذه الفئة Class فربما سيفترض أن إدخاله للعمر 0 لن يسبب اي مشاكل، لكن هذا افتراض خاطئ، ربما في أحد دوال هذه الكلاس هناك عملية قسمة لمتغير آخر على هذا العمر، و القسمة على صفر تؤدي إلى حدوث خطأ، والمشكلة أن مثل هذه الأخطاء عادةً لا تظهر مباشرة لـ مستخدم الفئة Class، إنما يظهر الخطأ فيما بعد وربما أثناء عمل البرنامج لدى المستخدم النهائي وهي ما تعرف بإسم Run-Time Error، لكن لو قمنا بالسماح باستخدام هذا المتغير من خلال دالة فنستطيع التحكم وتنبيه المطور مباشرة عند ادخاله للرقم 0 للعمر، أو تحويل الـ 0 الى 1 او غيرها .. ولأن مطور الفئة Class يعرف آلية عملها بالتفصيل فيجب أن يحمي المتغيرات الموجودة داخلها.

الوراثة (Inheritance):

الوراثة هي عملية إنشاء كلاس جديد بنائاً على كلاس سابق، أو بمعنى آخر اشتقاق، وتبرز أهمية الوراثة في تمكيننا من إعادة استخدام أكواد مكتوبة سابقاً، وتعديل بعضها أو إضافة خصائص جديدة بدل من إعادة كتابتها كل مرة، وتسمى الفئة Class التي نرث منها بالأب Parent والتي نُورِّثُ إليها بالابن Son . لنفهم أهمية الوراثة نأخذ المثال التالي، لنفرض أن هناك فئة Class تقوم باستخدامها لإظهار زر على الشاشة، وهذه الفئة كتبها مبرمج غيرك وهي تعمل بكفائة، وداخل تطبيقك تحتاج لإضافة خصائص إضافية لهذا الزر ، أو خصائص غير موجودة حالياً، لنقل مثلاً خاصية النقر المزدوج، في هذه الحالة لديك عدة خيارات قد تستطيع القيام بها:
1 – الدخول إلى تلك الكلاس والقيام بتعديله وقد تقوم بتعطيل شيء فيها دون قصد.
2 – القيام بنسخ الكود الخاص بهذه الكلاس ولصقها ثم إجراء التعديلات واستخدام هذه الكلاس الجديدة، لكن في هذه الحالة أي شيء نقوم بتغييره او تطويره، او اصلاح بعض الاخطاء على الكلاس الأصلية يجب أن نغيره على هذه ايضاً، وهذا فيه إضاعة كبيرة للوقت.
3 – الوراثة ! عمل كلاس جديدة ترث الكلاس القديمة بكامل خصائصها، ثم تقوم بإضافة الخاصية الجديدة فقط، وبهذه الطريقة نتأكد من استمرارية عمل الكلاس القديمة بلا اي مشاكل، واي تطويرات على الكلاس القديمة ستنعكس ضمنياً على هذه الكلاس.

تعدد الأشكال (Polymorphism):

ويعني أن الكائن يمكن أن يتخذ أكثر من شكل، والفكرة ببساطة أن مجموعة كائنات ترث خصائصها من أب واحد، لكن كل منهم يقوم بتعديل هذه الخصائص لـ تقوم بأمر مختلف.
ومن أهم استخداماته هو القدرة على تمرير هذه الكائنات المختلفة إلى نفس الدالة، أي لو كان لدينا الكائنات التالية: مربع، مستطيل و مثلث، ولدينا كلاس اسمه Area للتعامل مع المساحات وفيها خاصية طباعة مساحة الشكل على الشاشة، بدون مفهوم تعدد الأشكال سيكون علينا أن نقوم بعمل ثلاث دوال لطباعة مساحة كل شكل من هذه الاشكال، مثلا PrintSquareArea و PrintTriangleArea و PrintRectangleArea لكن بتطبيق مبدأ تعدد الأشكال بإمكاننا الاكتفاء بـ دالة واحدة مثلا PrintArea وتستطيع استقبال جميع الاشكال، لانهم بالنهاية مشتقين من كائن واحد، وهذا ممكن ببساطة لان جميع الكلاسات الخاصة بهذه الاشكال يجب ان ترث من كلاس أب يمتلك الخصائص التي نحتاجها وليكن اسمه Shape مثلاً ولديه دالة CalculateArea لحساب المساحة، ثم تقوم كل كلاس ترث منه بتعديل طريقة حساب المساحة بما يناسبها، لكن المهم انها تمتلك هذه الدالة ! فتستطيع دالة الطباعة استدعاء الدالة على أي شكل يمرر لها دون الاهتمام بـ نوعه، المهم أنه يرث من اب يمتلك هذه الدالة فبالتأكيد أن الكائن الابن يمتلكها ايضاً.

تطبيق البرمجة كائنية التوجه OOP بواسطة #C

هناك بعض المصطلحات المرافقة للبرمجة كائنية التوجه التي يجب عليك كمطور الإلمام بها ومعرفتها، سنقوم بالتعرف عليها وإستخدامها مباشرة بشكل أسطر برمجة بإستخدام لغة C# ، وهنا  أهمها تباعاً :

1 – الفئات والكائنات (Classes and Objects)

الفئة هي عبارة عن نموذج أو وصف للكائن (blueprint)، أما الكائن فهو عبارة عن نسخة من هذه الفئة (instance)، على سبيل المثال، لو كان لدينا فئة Student فإننا نقوم بإنشاء كائنات من هذه الفئة كما يلي:

Student std = new Student();

فهنا لدينا Student هي النموذج العام، ثم قمنا بإنشاء كائن Std وهو مستقل بذاته، أي إذا قمنا بانشاء 10 كائنات، فإن التعديل على خصائص أحدهما لا يؤثر في الآخر، لكن التعديل على الفئة نفسها ينعكس على جميع الكائنات المنشئة منها. وهنا طريقة إنشاء الفئة Class في لغة #C :

Class Student
{
}

تتكون الفئة Class من التالي :
الخصائص والمتغيرات (properties): وهي عبارة عن البيانات التي يتم تخزينها داخل الفئة Class
الدوال (methods): ويمكن ان نقول انها تمثل سلوك هذه الكلاس أو بعبارة أبسط المهام والأمور التي تقوم بها هذه الكلاس، مثلا دالة Max لإيجاد الأكبر بين رقمين.
الأحداث (events): والأحداث عبارة عن قنوات للتواصل بين الفئات والكائنات المختلفة.

2 – الخصائص والمتغيرات Properties & Variables

يمكن أن نقوم بإضافة متغيرات Variables للفئات Classes في لغة ال #C كما يلي :

Class Student
{ 
       public int age;
}

لكن كما تلاحظ فقد قمنا بانتهاك أحد مبادئ البرمجة كائنية التوجه، والتي تم شرحها في بداية المقالة، وهو التغليف Encapsulation ، لذلك يجب أن نحول متغير العمر الى شيء محمي ويبقى داخل الفئة وهو ما يعرف بالإسم private  كما يلي :

Class Student
{ 
      private int age;
}

هنا يأتي دور الخصائص Properties والتي تقوم بتعديل أو طباعة قيمة هذا المتغير وتحافظ عليه من أي تعديل خارجي، حيث يمكننا تعريفها داخل لغة #C كالتالي :

Class Student
{
	private int _age;
	public int Age
	{
		get {return _age;}
		set 
		{
			if(value <= 0)
				_age = 1;
			else 
				_age = value;
		}
	}
}

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

Class Student
{
	Public int Age { get; set; };
}

3 – الدوال Methods

الدالة عبارة عن حدث أو مهمة تقوم بإجراءات وظيفية داخل الفئة وغالباً تتعامل مع المتغيرات والخصائص الداخلية، فمثلاً تأخذ العمر وبناءاً عليه تحدد شيء معين، وتكتب بهذا الشكل

public int Method(string param)
{
// code
}

ويمكن للفئة Class امتلاك أكثر من دالة تحمل نفس الاسم، لكن بشرط اختلاف عدد المتغيرات الممررة لها Parameters او اختلاف نوعها، وهو ما يعرف ب overloading ، كالتالي :

public int Method(string param) {};
public int Method(int param) {};

4 – دوال البناء Constructors

دالة البناء هي دالة يتم استدعائها بشكل تلقائي عند إنشاء الكائن باستخدام new ويجب ألا تقوم بإرجاع أي قيمة، وان يكون اسمها نفس اسم الفئة Class، كما يمكنك انشاء اكثر من دالة بناء من خلال ال overloading وعادة تستخدم دالة البناء لتهيئة الكلاس ووضع قيم أولية لـ متغيراتها قبل البدء باستخدامه.وهذا مثال عليها

public class SampleClass 
{
	public SampleClass()
	{
	}
	public SampleClass(int age)
	{
	}
}

كما تلاحظ، قمنا بإنشاء دالتي بناء، الاولى سيتم استدعائها عندما ننشئ كائن بهذا الشكل

SampleClass sc1 = new SampleClass();

والثانية عند تمرير قيمة مثل

SampleClass sc1 = new SampleClass(22);

5 – الكلاسات المتداخلة Nested Class

بإمكاننا تعريف فئة Class داخل فئة أخرى، وتسمى nested class اي فئة داخلية أو متداخلة

class Main
{
	Class Nested
	{
	}
}

كما نلاحظ هنا الكلاس Nested موجودة داخل الكلاس Main ونستطيع استخدامها بهذا الشكل

Main.Nested nested = new Main.Nested();

6 – سماحية الوصول (Access Modifiers)

نستطيع التحكم بإمكانية الوصول إلى المتغيرات والدوال داخل الكلاس عن طريق ال Access Modifiers ، وهناك خمس أنواع :
عام (public): نستطيع الوصول إلى هذا المتغير أو الدالة من اي مكان في المشروع، او حتى من خلال مشروع آخر يعتمد على هذا المشروع.
خاص (private): نستطيع الوصول إلى هذا المتغير أو الدالة من خلال نفس الكلاس فقط، وليس من أي مكان آخر.
محمي (protected): نستطيع الوصول إلى هذا المتغير أو الدالة من نفس الكلاس او من كلاس أخرى مشتقة منها (أي ترث منها كما شرحنا سابقاً).
داخلي (internal): نستطيع الوصول إلى المتغير أو الدالة من نفس المشروع فقط، أي أن المشاريع الأخرى التي تعتمد على هذا المشروع لا تستطيع الوصول اليه.
داخلي محمي (protected internal): نستطيع الوصول إلى هذا المتغير أو الدالة من نفس المشروع أو من كلاس موجودة في مشروع آخر تشتق (ترث) من هذه الكلاس.

تم كتابة الجزء الاول من المقالة بواسطة Ward Mahmoud وترجمتها إستناداً إلى مقالة أصلية هنا، نلقاكم في الجزء الثاني قريباً إن شاء الله.

post

#18 الفئات Classes – البرمجة بواسطة #C

رمز فتح مرحلة هذا الدرس في تطبيق طورني : IOR

تَعلُمُ البرمجةِ للمبتدئينَ كلياً بواسطةِ #C –  التعامل مع الفئات Classes

الفئات Classes :

ما هو ال Class وكيف يمكن تعريف خصائص Properties له وكيف يمكن إستنساخ مجسمات منه للتعامل مع مشروعنا، هذا ما ستتعرف عليه في هذا الدرس إن شاء الله

كيف يمكننا تعريف متغيرات تشترك في صفات معينة ، ما هو الكلاس ، و كيف يمكننا استنساخ مجسمات منه ؟

هذا ما سوف نتعرف عليه في هذا الدرس بعد الفاصل ان شاء الله

 

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

بسم الله الرحمن الرحيم

درسنا اليوم عن الفئات ، طبعا هناك فكرة أريد إيصالها ، و سنلاحظها في الدروس القادمة

هناك بعد المصطلحات التي إن ترجمتها إلى العربية ، فسيكون هناك مشكلة في فهمها ، و ستفقد المهمة الأساسية لها .

تعريف الـ Class

الفئات هو المصطلح الذي وجدته معمماً في الدروس ، و هو المعرف على موسوعة ويكيبيديا .

فالـ Classes هو بتعريفه هو عبارة عن نوع جديد يحتوي على ميزات غير موجودة في الأنواع التقليدية و العادية

رأينا أنه في الدروس سمعنا كثيراً بمصطلح الـ Class  ، مثل الـ Console Class و استطلعنا أن نستعمل دوال منه مثل Write , Read , Clear

و تعاملنا في الدروس السابقة مع الكلمة new و التي قلنا أننا سنحاول تفصيلها لاحقاً قدر الإمكان .

الـ Class هو أهم شيء موجود في البرمجة كائنية التوجه OOP ، و استخدام الكلاس في هذا النوع من البرمجة يحتاج إلى شروحات كثيرة و طويلة ، لكن في هذا الدرس سنحاول تلخيصها و التعريف بموجز عنها ، كي نتمكن من استخدامها في مشاريعنا ، و ذلك لأنها الأساس في المشاريع الكبيرة .

 

نبدأ بإنشاء مشروع جديد كما تعلمنا سابقاً و لا ننسى التأكد من اختيار Visual سي شارب و اختيار Console App

و من باب التأكيد تكلمنا أن الدالة void Main هي الدالة التي يبدأ بها التطبيق بتنفيذ اسطره البرمجية ، و سنتعلم في المستقبل كيف يمكن تغييرها ، فليس شرطاً أن تكون هي الدالة الأساسية ، فيمكننا استدعاء دالة أخرى .

 

كما تحدثنا سابقاً ، فالكلاس يحيط بنا في كل تطبيق ، فمن أول تطبيق قمنا بكتابته في هذا السلسلة كان الكلاس موجوداً

و لكننا لم نعره انتباهاً لأنه يحتاج معرفة الأساسيات لنتمكن من فهمه .

طبعا فكرة الكلاس أو فكرة أن تقوم بإضافة مميزات أو خصائص معينة للـ Object كالتالي :

 

لنفرض أن لديك معرضاُ للسيارات و طلب منك أن تقوم بعمل إحصاء لسيارات معينة

و لو طلبت منك عمل هذا بمعرفتك البرمجية السابقة ، فستقوم بتعريف 3 متغيرات ( المتغير الأول يشير إلى اسم السيارة ، و المتغير الثاني سيشير إلى موديل السيارة ، و المتغير الثالث سيشير إلى السنة التي صنعت السيارة فيها )

و لاحظو أن هذه الثلاث متغيرات ستكون خاصة بالسيارة الأولى ، و بالطبع في المعرض لا يوجد سيارة واحدة .

فإن أردت أن أقوم بإضافة سيارة أخرى ، فما الذي سأقوم بإضافته ؟؟
كالمرة السابقة ، سأقوم بإضافة 3 متغيرات جديدة بنفس وظائف المتغيرات السابقة للسيارة الأولى .

و ذات الشيء لإضافة سيارة ثالثة .

لاحظوا أنني أقوم بإضافة متغيرات كثيرة ، ففي كل مرة أقوم بإضافة 3 متغيرات جديدة ، و أنا كمبرمج أحفظهم فقد قلت له car1 فهي السيارة الأولى ، ثم الشيء الموجود بعد الرقم 1 هو تابع للسيارة الواحدة .

حسناً .. نفترض أنني قمت بعملي هذا و وضعت القيم و تم الأمر بشكل صحيح

و لكن لنفترض أنني قمت بإدخال 50 سيارة على سبيل المثال ، و بعد ذلك وجدت أنه يلزمني إضافة نوع جديد ، أو خاصية جديدة لم اكن منتبهاً لها في البداية ، كإضافة اللون مثلاً فسأقوم بتعريف متغير نصي ، و إن أردت أن أقوم بعمل الخاصية لكل السيارات فسأضطر إلى تكراراها عدة مرات . و لكن هذه الطريقة تقليدية و قاتلة و مضيعة للوقت ، فهي طريقة غير عملية .

لذلك جاء مفهوم الـ Classes ، ألا و هو كيفية بناء فئة معينة تحتوي على خصائص مشتركة ، و يمكن عمل نسخ كثيرة منها ، و يمكن أن نعطي مثالاً للتوضيح ، فلنفترض أن الكلاس عبارة عن قطاعة كعك ، و قطاعة الكعك هي قطعة من الألمنيوم ، فتضعها على الكعك فيخرج معك أشكال مشابهة لشكل القطاعة ، هذه القطاعة لا تستطيع أن تأكلها ، لكن أنت تريد القع التي قمت بقطعها باستخدام هذه الأداة ،

إذا لنقوم بكتابة الكلاس سنقوم بحذف الأسطر السابقة و نبدأ بكتابة الكلاس الخاص بنا ، و نلاحظ أن الكلاس يكتب خارج الكلاس السابق ، فلا يمكن كتابة الكلاس داخل كلاس اخر !

 

الآن أريد تعريف كلاس جديد في منطقة موازية للكلاس الرئيسي ، و هو في داخل الـ namespace الذي قمت بتعريفه منذ البداية .

سأقوم بكتابة الكلاس و يمكنكم الحاق بي …

هنا سأعطيكم ميزة موجودة في برنامج Visual Studio  و هي ميزة جيدة جداً .لاحظوا أنني قمت بكتابة property و هي الخاصية الرئيسية الموجودة في هذا الكلاس ، يمكنني أن أقوم بعملية نسخها لكن من باب التسريع يمكن استخدام الـ Quick Action التي تحدثا عنها سابقاً ، فتكتب prop اختصاراً لـ property ثم تضغط زر Tab مرتين ، فتجد أنه قام مباشرة بعملية إضافة الشكل الكامل للكلاس . و قد تعرفنا عليها سابقاً في درس الـ For Loop حيث قمنا بكتابة for و مباشرة نضغط على Tab مرتين ليقوم بإضافة الشكل الكامل.

إذا نلاحظ هنا أنه من خلال الزل Tab  يمكنني أن أنتقل بين الأماكن الصفراء التي تحتاجها ، و طبعاً int ليس شرطاً أن يكون int فمثلا الخاصية الثانية في السيارة هي من النوع string و ليس int  ، فلذلك سأستبدل الـ int  بـ string ، و أقوم مباشرة بالضغط على Tab للانتقال إلى myProperty  لأقوم بتعديلها إلى Model  . و عند الانتهاء أقوم بعمل Enter  مرتين . إذاً من أجل السرعة بإمكانكم استعمال هذه الميزة ، و بالطبع في البداية ستأخذ وقتاً حتى تعتادوا عليها ، لكن لاحقاً ستكون شيئاً أساسياً .

 

إذا نتابع انشاء الكلاسات المطلوبة للسنة و اللون ، و هكذا قمت بتعريف الكلاس الذي اسمه car بهذه الخطوات ، و هذا الكلاس يحتوي على 4 خصائص ، و التي هي الشركة المصنعة و الموديل و السنة و اللون الخاص بها .

الآن إذا أردت استخدام هذا النوع ، و هذا النوع يشبه قطاعة الكعك التي تحدثنا عنها قبل قليل ، فأنا لن أذهب إلى القطاعة و آكلها ! و بهذا لا يمكنني استخدام النوع في تطبيقي مباشرة ، فأنا أحتاج إلى المجسم أو الشيء الذي ينتج من استخدام هذه الأداة ،

لذلك نعود للدالة الرئيسية void Main و سنقوم الآن بعملية استنساخ أو بناء مجسم جديد من النوع car كالتالي :

لاحظوا أنني سأقوم بكتابة Car بحرف كبير و أضع هنا متغير جديد ، و بهذا السطر قمت بتعريف متغير جديد من النوع Car و اسمه myCar و تحدثنا سابقاً عن تعريف المتغيرات ، فكنا نقوم بتعريف متغيرات من النوع int  أو  string  …

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

إذا بعد أن قمت بتعريف متغير ، و لكي أقوم بإنشائه و التي هي عملية Initialization لاحظوا أنني قمت باستخدام كلمة new ، فنحن نقوم بعملية إنشاء أو استنساخ هذا المجسم من شيء كبير ، ألا و هو الكلاس .

إذاً ..قمت بعملية تعريف و عملية Initialization مباشرة .

لكي أقوم باستخدام هذا المجسم الجديد ، لاحظوا أنني أستطيع الدخول إلى كل الخصائص التي كتبتها هنا من الـ Member Access أو من خاصية الـ IntelliSense ، فإن قمت الآن بكتابة اسم المتغير ثم أضفت نقطة ، فسأحصل على الخصائص التي قمت أنا بكتابتها ، الشركة المصنعة و الموديل و اللون و السنة . هذه الخصائص عليها icon مثل المفتاح ، لتشير إلى أن هذه الخاصية قمت أنا بإضافتها

إذا سأقوم بإدراج قيم إليها ، فقد قمت بتعريف متغير ، و أريد أن اعطيه قيمة للخصائص الموجودة ،

لذلك سأقوم بوضع الشركة المصنعة BMW على سبيل المثال و الموديل و السنة و اللون .

لاحظوا في الجمل الأربع السابقة قمت بإعطاء قيم للخصائص التي قمت بكتابتها .

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

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

إذا في هذه الأسطر الأربع تكلمنا أنه قمنا بعملية وضع قيم ، الآن كيف يمكنني قراءة هذه القيم ،

الأمر بديهي و تكلمنا عنه سابقاً .

إذا قمت بتنفيذ التطبيق فسيقوم بطباعة اسم الشركة المصنعة و موديل السيارة و السنة و اللون

هذا كان بشكل سريع مفهوم الكلاس ، طبعا الكلاس يحتوي على مفاهيم أكثر و سنتعرف على جزئية واحدة منها بعد قليل ، و نترك ما تبقى للمحاضرة التالية ان شاء الله .

إذا هنا قمت بتعريف الكلاس و إضافة خصائص و إسنادها في البرنامج

الآن بإمكانك طالما أنك أنشأت نوع جديد ، و كما تكلمنا سابقاً إذا كان لديك Method فبإمكانك أن ترسل لها parameter لاستخدامه داخل الدالة ، ففي الدروس السابقة أرسنا قيمة int  و بناء عليها حددنا ما الذي يريد المستخدم ،

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

لاحظوا الآن سنتعامل مع نوع جديد من أنواع البيانات ، و هو decimal ، و هو نوع يشبه الـ float إلا أنه يحتوي على خانات أكبر ، و هو أدق ، و يستخدم عادة في التعاملات المالية ، لأنه يحتوي خانات أكثر من float ، فحجم الـ float  في الذاكرة 32 بت ، أما الـ decimal فحجمه تقريباً 128 بت .

لاحظوا هذه الدالة تقوم بعملية ارجاع قيمة decimal  ، لكن هنا أريد أن أقوم بعملية إعطاء أو ادخال متغير من النوع Car و نسميه أي اسم ، و هذا المتغير سأقوم باستخدامه داخل الدالة ، فإنا هنا لا أقول له myCar بل أقول له سأعطيك متغيراً من النوع Car  ، و نسميه أي شيء ؛ هنا سأسميه car بحرف صغير .

إذاً هنا قمت بتعريف متغير جديد ، و سأقوم باستخدامه في داخل الدالة ، إذا سوف أذهب و أقول له كالتالي :

نفترض أنني مبدئياً سأقوم بتعريف متغير من النوع decimal باسم carValue و أسند إليه قيمة مثلاً 1000 دولار ، لاحظوا هنا كما تعرفنا سابقاً عندما يكون لديك فاصلة ، فيجب إضافة الحرف m لتمييزه ، عن النوع float  .

إذا قمت بتعريف متغير و بماشرة سأقوم بإرجاع القيمة .

إذا هذه الـ Method تقوم بأخذ نوع Car و بناء عليه نقوم بإرجاع قيمة معينة ، و لاحظوا إن قمت بعملية طباعة الدالة MarketValue و قمت بإسناد الـ myCar الذي قمت بتعريفه قبل قليل ، و قمت بتشغيل البرنامج ، فإنه سيقوم بإرجاع القيمة الافتراضية . أنا هنا لم أحدد أبداً ، أنا فقط أرسلت المتغير ، و لم أقم باستخدام أي Property خاصة به ، فبما أنني قادر على ارسال نوع الـ Car إلى هذه الـ Method  ، فأنا سأقوم بإضافة قيمة معينة .

نكتب جملة شرطية ، إذا كانت car.Year أقل من 1980 فسعرها سيكون مثلاً 200.5  و لا ننسى الحرف m

ثم نتابع بكتابة الجملة else فالسيارة سعرها 2000.50 مثلاً ، و أيضاً لا ننسى الحرف m .

نقوم بتشغيل البرنامج ، لاحظوا أنه قام بأخذ الـ object الذي قمت تعريفه ، و تعامل مع الـ year  التي قمت بإسنادها أيضاً ، مباشرة قام بتحديد القيمة الراجعة من الـ Property التي تم تعريفها في الكلاس في الكلاس و بناء عليه قام بتحديدها .

الشيء الذي أريد توضيحه هنا في هذه الدالة ، أنه ليس فقط بإمكانك أن تقوم بكتابة الـ Property في الكلاس ، يمكنك أيضاً كتابة Method كاملة تقوم بإرجاع قيم ، فهنا يمكنني أن أقول له كالتالي :

في داخل هذا الكلاس لا اعرف ما هي القيم ، أنا أقوم فقط بأخذ الـ  Propertyو لا أعرف ما هي قيمة الـ object التي أتت لاحقاً و أخذت قيماً متغيرة ، لذلك أقول له في الفئة الخاصة بي إذا كانت السنة للسيارة أقل من قيمة ما ، فقم بإرجاع هذا المتغير ، و لاحظوا أنني قمت بوضعها public ،  و سنتكلم لاحقاً عن الفرق بين public  و private .

إذا سأعود هنا و سأقوم بعمل Comment  لهذا السطر و أقول له كالتالي :

أريد أن تطبع myCar.MarketValue و هذه دالة ترجع قيمة decimal .

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

 

إذا الكلاس بشكل موجز عبارة عن فئة جديدة نحن  نقوم بتعريفها ، و من ثم بعد انتاجها ، نحن نقوم باستنساخ مجسمات أو Object  منها و وضعها في الذاكرة ،  و أريد أن أوضح أن الكلاس له مكان معين في الذاكرة ، لكن عندما أقوم بإنشاء مجسم أو Object جديد فإنه يقوم بوضعهم في أماكن مختلفة في الذاكرة ، و كأن هذا الـ Car هو int  أو string ، إذا أنا أقوم بعملية بناء مجسمات من هذا الكلاس و أقوم بإعطائها قيماً و التعامل معها .

هذا بشكل موجز و سريع هو مفهوم الكلاس ، و الكلاس له مفاهيم متقدمة جداً و سنتعرف عليها رويداً ، فلا أريد وضعها كلها في درس واحد ، حتى لا يصبح لديكم شعور بأن مصطلح الكلاس شيء معقد و صعب . و لكن الكلاس هو فن جميل في داخل البرمجة ، و أعطى بعد جديد للتطبيقات التي يمكن أن نقوم بأشياء كبيرة جداً بخصائصه هذه ، فيمكن أن تقوم بعملية حماية للبيانات الموجودة بالداخل ، و بإمكانك أن تقوم بعملية استنساخ من نفس الكلاس و تقوم بعمل تعريف لكلاس آخر ضمنياً ، و إلى هنا نصل إلى نهابة الدرس .

مصطلحات الدرس :

Properties / Property  :

Class :

OOP :

Object :

namespace :

Quick Action :

Initialization :

IntelliSense :

parameter :

float :

decimal :

public :

private :

program :

 

 

الأسطر البرمجية :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SimpleClasses
{
    class Program
    {
        static void Main(string[] args)
        {
            Car myCar = new Car();
            myCar.Make = "BMW";
            myCar.Model = "Sedan";
            myCar.Year = 2017;
            myCar.Color = "Black";

            Console.WriteLine("{0} {1} {2} {3}", 
                myCar.Make, 
                myCar.Model, 
                myCar.Year, 
                myCar.Color);

            //Console.WriteLine(MarketValue(myCar));
            Console.WriteLine(myCar.MarketValue());

            Console.ReadLine();
        }

        private static decimal MarketValue(Car car)
        {
            decimal carValue = 1000.0m;
            if (car.Year < 1980)
                carValue = 200.5m;
            else
                carValue = 2000.50m;

            return carValue;
        }

    }
    class Car
    {
        public string Make { get; set; }
        public string Model { get; set; }
        public int Year { get; set; }
        public string Color { get; set; }

        public decimal MarketValue()
        {
            decimal carValue = 1000.0m;
            if (Year < 1980)
                carValue = 200.5m;
            else
                carValue = 2000.50m;

            return carValue;
        }
    }
}

post

#17 التاريخ والوقت DateTime – البرمجة بواسطة #C

رمز فتح مرحلة هذا الدرس في تطبيق طورني : NYU

تَعلُمُ البرمجةِ للمبتدئينَ كلياً بواسطةِ #C –  التعامل مع التاريخ والوقت DateTime

كيفَ يُمْكِنُنا التَّعامُلُ مَع التاريخ والوقت

كيف يمكننا قراءة التاريخ الحالي ؟  و كيف يمكننا قراءة عدد الأشهر من تاريخ معين ؟ و كيف يمكننا إيجاد الفرق بين تاريخ و تاريخ آخر ؟ هذا ما سوف نتعرف عليه في هذا الدرس بعد الفاصل إن شاء الله . السلام عليكم و رحمة الله و بركاته ، و أهلاً و سهلاً بكم في درس جديد من دروس سلسلة تعلم البرمجة للمبتدئين كلياً بواسطة السي شارب ، تحدثنا في الدروس الماضية عن كيفية التعامل مع الـ Methods ، و كيفية كتابة النصوص ، و كيفية عمل Format للنصوص و كيفية التعديل عليها و أخذ أجزاء منها ، في درس اليوم سنناقش قضية مهمة ، و هي التعامل مع التاريخ و الوقت ، ففي بعض أنواع التطبيقات يجب عليك أن تكون على دراية بكيفية تعريف متغيرات من نوع التاريخ و الوقت ، و كيفية التعامل معها لأخذ معلومات خاصة بها ،

إذاً كما تعلمنا سابقاً نقوم بإنشاء مشروع جديد ، تكلمنا كثيراً أن المكان المخصص لكتابة الأكواد البرمجية هو بين قوسي الدالة void Main ، و تكلمنا أنه يجب أن نستخدم الدالة ReadLine في نهاية التطبيق لنتمكن من مشاهدة النتائج قبل إنتهاء التطبيق.

لتعريف متغير من النوع تاريخ نقوم بكتابة نوع المتغير DateTime  ثم نكتب مسافة ثم اسم المتغير و ينتهي بالفاصلة المنقوطة ، و هذا مشابه لطريقة تعريف المتغيرات من الأنواع الأخرى كالنوع int  و  string ، و نلاحظ هنا  أن الكلمة DateTime التي ظهرت باللون الأزرق الفاتح هي نوع المتغير ، و هو مشابه للأنواع الأخرى ، لكن له صيغة معينة ، لاحظو أنني قمت بتعريف المتغير ، و الآن أريد أن أسند  قيمة إليه . و أفضل طريقة للإضافة تاريخ للمتغير هي إضافة التاريخ الحالي ، لذلك سأقوم بكتابة إشارة الإسناد ، ثم أكتب DateTime.Now ثم الفاصلة المنقوطة ، نلاحظ أنه بمجرد أن قمنا بكتابة النقطة بعد اسم الكلاس DateTime قمت بإضافة الكلمة Now لأخذ التاريح الحالي ، و لو قمت بطباعة المتغير ، سيطبع البرنامج التاريخ و الوقت ، الصيغة التي قام بطباعتها هنا اعتمدها عندما قمت باستدعاء DateTime.Now قام باعتماد الصيغة الموجودة على الجهاز ، و الصيغة تختلف بين بلد و بلد آخر ، فمثلاً في الولايات المتحدة الأمريكية يبدأ بكتابة الشهر بدل اليوم .

و هنا صادف أن التاريخ الحالي 8.8 ، و في هذه الحالي قد لا ندري أهذا هو الشهر أو اليوم ، و هنا في الجهاز الذي استخدمه النظام يبدأ باليوم ثم الشهر و بعده السنة ، و نلاحظ أنه قام بطباعة الساعة بنظام 24 ساعة ، و قد يختلف هذا أيضاً من بلد إلى آخر ، فهناك بلدان تتعامل بنظام 12 ساعة و يقوم بإضافة PM  و  AM  ، فهذا يعتمد على طبيعة النظام الذي تستخدمه على جهازك .

الـ Methods المستخدمة في التعامل مع التاريخ و الوقت :

الآن .. هناك Methods في هذا الكلاس يمكن أستخدمها لطباعة شكل معين من التاريخ ، فنلاحظ أنه قام بطباعة التاريخ مع الوقت ، ماذا لو أردت طباعة الوقت فقط . أو طباعة التاريخ فقط . و سنتعرف على هذه الدوال واحدة تلو الأخرى .

في السطر الذي قمنا بطباعة المتغير به ، و بمجرد وضع النقطة التي أسميناها الـ Member Access ستظهر الدوال التي يمكننا استخدامها  أو العديد من القيم التي يمكن أن تحصل عليها .

فلو قمت بوضع ToShortDateString و قمت بطباعة الناتج ، فلاحظو أنه سيعطيني التاريخ فقط و بالصيغة المختصرة ، و التي هي عبارة عن أرقام ، فنلاحظ أنه يظهر 8.8.2017 .

لكن هناك إمكانية للحصول على نسخة غير مختصرة و ذلك باستعمال الدالة ToLongDateString و قمت بطباعة المتغير ، فسيظهر التاريخ بشكل كامل و سيكتب اسم الشهر و اسم اليوم كذلك ، و يسمى هذا التاريخ الطويل ، لأنه لم يكتفِ بوضع اليوم ثم نقطة ثم الشهر ثم نقطة ثم السنة ، بل قام بوضعها بالصيغة الطويلة

و بالمثل هناك دالة يمكن استخدامها ، ألا و هي ToShortTimeString ، و هي تقوم بطباعة الساعة و الدقائق فقط بالشكل 19:13

و بالمثل إذا قمت بكتابة ToLongTimeString فسيطبع الساعة ، و الدقيقة ، و الثانية كذلك .

 

ليس هذا فحسب ، بل لديك إمكانيات كذلك بالتعامل مع إضافة ساعات أو أيام مع هذا التاريخ ، فإن قمت بإضافة Add  بعد النقطة فسيظهر لدينا AddDays و AddHours و AddMinutes و  AddSeconds  و AddYears ، فهناك عدة دوال لإضافة الشيء الذي تريده .

فمثلاً أريد إضافة 3 أيام للتاريخ الحالي ، ففي الأعلى قمنا بأخذ الوقت الحالي عند كتابة الكلمة Now . و مباشرة سأقوم بطباعة الوقت الحالي و لكن سأقوم بإضافة 3 أيام إليه ، و ذلك باستعمال الدالة AddDays(3)
و بتنفيذ التطبيق سيقوم بطباعة التاريخ بعد زيادة 3 أيام ، فتاريخ اليوم هو 8.8.2017  لكنه قام بطباعة 11.8.2017

و ذلك لأنني استخدمت الدالة ()AddDays  عندها قام بإضافة الرقم الموجود بين قوسي الدالة إلى التاريخ الحالي .

 

نلاحظ الآن أن المتغير من النوع DateTime ، و الـ Method التي استعملناها إذا قمنا بوضع الماوس عليها سنلاحظ أنها تقوم بأخذ Value و ترجع قيمة تاريخ و ليس string ، و بما أنه قام بإرجاع قيمة تاريخ ، فبإمكاني أن أطلب مرة أخرى تحويله إلى تاريخ قصير ، و ذلك بوضع النقطة مرة أخرى و استعمال الدالة ToShortDateString ، و بتشغيل التطبيق نلاحظ أنه قام بزيادة 3 أيام كما طلبنا سابقاً ، و قام بطباعة التاريخ بالصيغة المختصرة .

و هنا أود أن أوضع قضية مهمة ، و هي أنه طالما أن النوع DateTime و تقوم بعمل Method تقوم بتحويله أيضاً إلى DateTime ،فبإمكانك أن تقوم بعمل سلسلة لا نهائية من الـ Methods .

 

أي بعد أن تقوم بعمل زيادة 3 أيام ، قم بعمل زيادة 3 ساعات ، و قم أيضاً بعمل زيادة شهرين ، و هكذا … ، فهذه السلسل يمكن أن تكون لا نهائية ، و هذه الفكرة ليست حصرية في الـ DateTime ، فكل المتغيرات أو كل شيء يقوم بإعادة شيء من نفس النوع ، فبإمكانك أن تعيد استخدام الـ Method الموجودة في ذات النوع

اذاً بالمثل يمكنني أن أطلب هنا أيضاً طباعة الوقت الطويل .

و بالمثل أيضاً يمكنني إضافة قيم سالبة ، بمعنى أنه سيقوم بطرح القيم السالبة من التاريخ الحالي . حسناً .. سأقوم بطلب خصم 3 أيام ، و عندها سيقوم بطباعة 5.8.2017   . و عند طلب الخصم نختار الدالة AddDays و نضع بين قوسيها قيمة سالبة مثل (3-) .

 

أيضا يمكنك أن تتعامل مع جزء ، أو أن تقوم بطباعة جزء واحد من التاريخ فقط ، بمعنى أنه إن قمت بوضع Month بعد النقطة فنلاحظ أن القيمة الراجعة هي integer ،بمعنى أنه سيقوم بطباعة رقم الشهر ، و بتشغيل التطبيق يظهر الرقم 8 و هو رقم الشهر الحالي .

هذا إن قمنا بتعريف متغير و اسناد قيمة التاريخ الحالي إليه . لكن ماذا لو قمنا بوضع تاري نأخذه من المستخدم أو استخدام تاريخ خاص بنا ؟

استخدام تاريخ خاص ، أو استعمال تاريخ يدخله المستخدم :

لعمل ذلك نقوم بعمل التالي ،

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

هنا سأقوم بإضافة السنة في البداية ، ثم الشهر ، ثم اليوم . لاحظو أنني قمت بتعريف المتغير من النوع DateTime و قمت بإسناد قيمة قمت أنا بإدخالها و لم استخدم التاريخ الحالي .

فإن قمت بطباعة الناتج نلاحظ أنه قام بتحويل الأرقام التي كتبتها إلى صيغة كاملة ، فقام بكتابة اليوم و الشهر و السنة ، و بطبيعة الحال لأنني لم أقم بكتابة الوقت قام بطباعته 00:00:00 .

أيضاً بإمكانك أن تقوم بأخذ قيمة من المستخدم و محاولة تحويلها إلى قيمة تحاكي التاريخ و الوقت ، فكما في السابق قمنا بتعريف المتغير و وضع إشارة الاسناد ، ثم إضافة اسم الكلاس ، ثم وضع نقطة الـ Member Access ، و نستخدم الدالة Parse التي تقوم بأخذ قيمة نص و تحويلها إلى Date

الآن سأقوم بوضع قيم التاريخ بين قوسي الدالة ، نلاحظ أن القيم – الموجودة بين الأرقام يمكن أن تكون مختلفة ، هنا في هذه الـ Method ليقرب القيمة إلى أقرب صيغة تاريخ ممكن أن تقوم معرفة ، و إذا قمت بوضع قيم غير مناسبة قد تحدث مشكلة . نقوم الآن بتشغيل التطبيق ، نلاحظ أنه رغم أنني قمت بكتابة خطوط بين الأرقام ، لكنه قام بأخذ الرقم الأول و حوله إلى تاريخ ، و أخذ النص الثاني و الثالث كذلك ، و قام بتحويل الخطوط إلى نقاط . و لو قمنا بتغيير الخطوط – إلى / سيقوم بذات العمل ، و سيحولها إلى نقاط .

حساب الفترة الزمنية بين تاريخين :

ماذا لو أردنا حساب الفترة الزمنية بين تاريخين ، بمعنى أريد حساب الوقت الذي عشته من تاريخ ولادتي إلى الآن.

بمجرد أن نقول أننا  نريد التعامل مع فترة زمنية ، فهناك متغير جديد اسمه TimeSpan ، و هو يقوم بأخذ تاريخين و يحسب الفرق بينهما .

الآن سأطلب منع حساب الفرق بين الوقت الحالي عن طريق DateTime.Now و إضافة إشارة – لطرح قيمة المتغير myBirthday .

إذا قمت بطباعة المتغير myAge  ستظهر لدينا أرقام ، ما هي طبيعة هذه الأرقام ؟ و كيف نقوم بقراءتها ؟

الـ TimeSpan يقوم بإرجاع قيم تبدأ بالأيام ، ثم بالساعات ، ثم بالدقائق ثم بالثواني ، ثم أجزاء الثواني ، فالرقم الأول من الجهة اليسرى هو عدد الأيام ، و الرقم الثاني 19 هو عدد الساعات ، و الرقم الثالث 26 هو الدقائق ، و الرقم 32 هو الثواني ، و الرقم الأخير في الجهة اليمنى هو أجزاء الثانية . و نلاحظ أنه قام بحساب الساعات من 00:00:00 لأننا لم نحدد الساعة بدقة كما قمنا بالتحديد بالنسبة للتاريخ .

نلاحظ أن المتغير TimeSpan ليس من النوع DateTime ، لذلك إذا قمت بإضافة النقطة سأحصل على عدد من الدوال الخاصة به ، و من هذه الأمور هو الـ  TotalDays ، و باختياره و تنفيذ البرنامج سيظهر عدد الأيام الكلي .

تطبيق يقوم بحساب الوقت بين تاريخين :

الآن بما أننا تعلمنا كيف نقوم بأخذ فترة زمنية و نقوم بطباعة قيم معينة ، دعونا نقوم بتحويل ما تعلمناه إلى تطبيق يمكننا استخدامه ، لذلك سنقوم بعمل تطبيق يسأل المستخدم عن تاريخ ولادته ، و نحاول تجزئة التاريخ بحيث أن البرنامج سيخبر المستخدم كم عدد مجمل الأيام و الساعات و الدقائق التي مرت منذ ولادته .

 

في بداية التطبيق سأقوم بطباعة جملة تسأل المتسخدم عن إدخال تاريخ ولادته ، و يفضل أن نقوم بإعطائه Hint  لكيفية ادخال التاريخ ، لأنه إذا حاول إدخال قيمة غير مناسبة سيحصل خطأ في التطبيق ، فهنا سنحاول أخذ التاريخ و تحويله إلى النوع DateTime ، و ذلك باستخدام الدالة Parse . و سنناقش ان شاء الله في دروس قادمة كيف نحل هذه المشاكل . و هنا سنقوم باستخدام الدالة Write لأننا نريد أن يطبع التاريح على نفس السطر .

الآن سأقوم بتعريف متغير من النوع  DateTime ثم إشارة الاسناد ، ثم سأستدعي الكلاس الأصلية و أقوم باستخدام الدالة Parse  لتقوم بمعالجة النص و تحويله إلى تاريخ ، و النص هو Console.ReadLine من المستخدم .
إذاً هنا قمت بطلب نص من المتسخدم ، و هذه القيمة حتماً ستكون string ، و هو في منطقة الـ Parse ، و الذي بدوره سيحاول تحويل القيمة إلى DateTime و التاريخ الذي حاول تحويله  سيقوم بإسناده إلى المتغير .

الآن سنقوم بتعريف متغير من النوع TimeSpan و سأكتب هنا الوقت الحالي و أطرح منه الوقت الذي أدخله المستخدم ، و يمكنني هنا أن أستخدم إشارة الطرح ، لكنني سأستخدم دالة جديدة ، و هي Subtract ، و هي تخبره أن يقوم بعملية طرح للتاريخ الثاني الذي سنضعه بين قوسي الدالة الجديدة ، وهو التاريخ الذي أدخله المستخدم .

و أخيراً سأقوم بطلب طباعة الوقت الكلي للوحدات الأيام ، الساعات ، و الدقائق .

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

الآن نقوم بتشغيل التطبيق و ادخال تاريخ الميلاد ، سيقوم البرنامج حينها بطباعة اجمالي الأيام و الساعات و الدقائق .

 

في هذا الدرس قمنا بالتعرف على كيفية أخذ التاريخ الحالي ، و كيف يمكننا تحويله إلى صيغ تتناسب مع المعطيات الموجودة لدينا ، و تعلمنا كيفية إضافة أجزاء إليه ، كإضافة ساعات أو دقائق إلى التاريخ الحالي ، و تعلمنا أيضاً كيف نقوم بالتحويل من نص و محاكاته إلى شيء يشبه التاريخ عن طريق الدالة Parse ، و تعرفنا أيضاً على قضية مهمة و هي الـ TimeSpan .

مصطلحات الدرس :

DateTime :

DateTime.Now :

Member Access :

Parse :

TimeSpan :

Hint :

Subtract :

تجد هنا الأسطر التي قمت بكتابتها خلال الدرس.

 

 

 

post

#16 التعامل مع النصوص Strings – البرمجة بواسطة #C

رمز فتح مرحلة هذا الدرس في تطبيق طورني : KUT

تَعلُمُ البرمجةِ للمبتدئينَ كلياً بواسطةِ #C –  التعامل مع النصوص Strings

كيفَ يُمْكِنُنا التَّعامُلُ مَع النُّصوصِ المُخْتَلِفة ، و كَيْفَ يُمْكِنُنا اقْتِباسُ جُزْءٍ مُعَيَّنٍ مِنْ نَصٍّ كامِلٍ ، و كيف يمكننا استبدال أحرف معينة في نص كامل ، و كيف يمكننا أيضاً معرفة عدد خانات الحروف في نص ما ؛ هذا ما سوف نعرفه في هذا الدرس بعد الفاصل إن شاء الله .

 

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

بسم الله الرحمن الرحيم

التعامل مع النصوص هو أمر أساسي في التطبيقات المستخدمة ، ففي كل مشروع يجب أن يكون هناك نصوص متداولة

و من خلالها يتم استخدامها في أمور معينة ، و عمل تعديلات عليها ، لذلك يجب أن يكون عندك معرفة بالأدوات و الـ Methods التي بإمكانك استخدامها للحصول على نص أو جزء من نص  ، و تعديل نص معين يمكنك استخدامه في البرنامد الخاص بك

 

نبدأ بإنشاء مشروع جديد بلغة #C من النوع Console App

في البداية سأكتب الأسطر التالية لأننا سنستخدمها بشكل أساسي

نلاحظ الآن أننا إذا قمنا بتشغيل البرنامج فلن يظهر شيء

حسناً ، إذا توجب علينا في حالة ما استخدام علامتي التنصيص في نص معين ، فإذا حاولت إضافة علامتي تنصيص فسيحدث مشكلة ، لماذا ؟

لأن الـ Compiler أخذ الجزء الأول و اعتبر العلامة الثانية في المنتصف هي نهاية النص الأول .

لذلك إذا أردت استخدامها فبإمكانك وضع Back Slash قبلها لكي تخبر الـ Compiler  أن هذه العلامة هي فعلاً رمز  سيستخدم داخل النص

نوضح الفرق بين الـ Slash و الـ Back Slash حتى لا يحصل التباس ، فالـ Slash  هي التي تكتب بالشكل (  /  )

أما الـ Back Slash فتكتب (  \  )

و نلاحظ أن الـ Slash /    لا تعمل عمل الـ Back Slash

الآن بعد إضافة الـ Back Slash و تشغيل التطبيق سنلاحظ أن البرنامج قام بطباعة علامتي التنصيص بشكل صحيح

و هذا هو أول استخدام للـ Back Slash

نقوم بتحويل الجملة السابقة إلى جملة ملاحظة .

 

الآن في هذه الجملة الجديدة أحتاج إلى النزول إلى سطر جديد … فإنني إن قمت بطباعتها فستظهر ف نفس السطر

لذلك إن أردنا النزول لسطر جديد فسنكتب   (Back Slash + n)      ، و عندها سيفهم الـ Compiler أنه عند هذه النقطة قم بالنزول إلى سطر جديد . و بتنفيذ البرنامج نرى أن المطلوب قد حدث فعلاً

 

نقوم بتحويل الجملة السابقة أيضاً إلى جملة ملاحظة .

 

الآن ماذا لو أردنا طباعة الـ Back Slash  في النص المراد طباعته ، فبوضعها مباشرة ضمن التطبيق ستظهر مشكلة في تطبيقنا ، و السبب أن الـ Compiler افترض أن هذا الـ Back Slash سيأتي بعده Character  معين لكي يقوم بعملية معينة ، لكن هنا في مثالنا الـCharacter التالي للـ Back Slash  هو مسافة فارغة

لذلك إن أردت استخدام الـ Back Slash قم بوضع Back Slash قبلها مباشرةً ، بالتالي فإن الـ Back Slash  الذي سيأتي ثانياً هو الذي سيتم طباعته ، أما المكتوب قبله مباشرة سيخبر الـ Compiler أن التالي هو عبارة عن نص وليس Back Slash escape Character

نلاحظ أننا إذا قمنا بتشغيل التطبيق سيقوم بطباعة المطلوب بشكل صحيح و دون مشاكل أو أخطاء

حسناً .. ماذا لو كان لدينا أكثر من Back Slash  في ذات النص ، فهل سأذهب إلى كل واحد منها و أضع قبله Back Slash إضافي ؟؟

بالطبع لا ، فبإمكانك الذهاب إلى ما قبل علامة التنصيص التي في بداية النص و إضافة الرمز @ ، و التي بدورها ستخبر الـ Compiler أن يعتبر كل رموز Back Slash الموجودة ضمن النص عبارة عن Character  عادي و ليس Back Slash Escape Character، و بالتالي تخبره أن يقوم بطباعة هذا الرمز

 

تكلمنا سابقاً عن :

;string myString = string.Format(“{0} = {1}” ,”First” , “Second” )

و كما تحدثنا ، إن أردت وضع قيمة معينة داخل نص فلا داعي لكتابة الجملة ثم أقوم بإنهائها ثم أضع القيمة ثم أعود لمتابعة الجملة ، بدلاً من ذلك سأقوم بوضع index  ، بحيث يقوم الصفر بأخذ أول خانة مباشرةً بعد الـ string

و الرقم 1 يقوم بأخذ الخانة رقم 2 ، و يتم فصل الخانات بفاصلة

بتشغيل التطبيق نلاحظ أنه أخذ أول قيمة بعد الـ string عند الرقم 0 ، ثم قام بأخذ القيم الثانية عند الرقم 1

و ليس من الضروري أن نقوم باستخدام 0 ثم 1 ثم 2 …. ، فبإمكاننا أخذ القيمة الأولى مرتين ، أو نقوم بطباعة القيمة الثانية ثم القيمة الأولى .

 

حسناً.. هذا المكان الموحود في الكود السابق {…}  له Format خاصة به ، من الممكن أن نقوم باستخدامها للتأثير على القيمة الموجودة هنا بطريقة معينة

نقوم بطباعة جملة جديدة و وضعنا بعد الرقم الحرف C فسيقوم بتحويل القيمة إلى الموجودة إلى قيمة عملة ، حيث سيضع قبلها علامة العملة الخاصة ببلد معين ، فإن قمت تستخدم الدولار فسيقوم بوضع العلامة $ ، و تتغير بحسب العملة المتبعة في بلدك ، لكن في جهازي أنا استخدم الليرة التركية ، فسيظهر علامة استفهام لأن رمز الليرة التركية غير معرف

 

الآن إذا كان لدينا رقم طويل بحيث يكون صعب القراءة ، كما تعلمنا في دراستنا فإن الرقم عادة يقسم بحيث يوجد فاصلة بين كل 3 خانات ، فإذا أردت أن يكون الرقم مفصولاً كذلك فيمكن أن نستخدم الحرف N ، عندها سيقوم بوضع الفواصل و النقط و عند التنفيذ نلاحظ أنه أضاف النقط بحيث يقسم كل 3 منازل ، و يضيف الفاصلة العشرية حتى لو لم تكن موجودة ، و يضيف الصفر إلى يمينها

 

ماذا لو أردنا استخدام النسبة المئوية percentage ، مثلا 20% , 30%

فيمكنك استخراجها باستخدام الحرف P و سنكتب في البداية كلمة percentage أو أي نص آخر

عندها سيقوم بتحويل الرقم  251. إلى 25.10%

 

ماذا لو أردت استخدام Format خاص بي

حيث سأقوم بإضافة الفواصل و النقاط و الشرطات بحسب رغبتي ، فيمكن عمل ذلك كما يلي،

ليكن لدي الرقم 1234567890 و اريد أن أحوله إلى رقم هاتف

لاحظو بعد النقطتين يمكننا طباعة الرقم كما نريد

فنضيف (###) ###-####)

كل إشارة من الإشارات السابقة هي عبارة عن خانة ، و بذلك قمنا بتنسيق الرقم كما أردنا ، و بتطبيق البرنامج سيطبع الرقم (123) 456-7890

و هذا يعد Format خاص

 

ماذا لو أردت التعامل مع نص حقيقي

لدي جملة و أريد أن آخذ أجزاء منها أو أقوم بعمليات عليها فماذا أفعل

سنعرف المتغير myString من النوع string  ثم أقول له

myString القديم سيصبح muString نفسه و اضع نقطة ، و بمجرد وضع النقطة ، و لأنه متغير نصي سيظهر لديك جميع الـ Methods الخاصة بـ string ، و بالطبع لكل نوع من أنواع البيانات Methods  خاصة به

يمكنني هنا أن أقوم بعملية قص عن طريق اختيار الدالة Substring التي اخترناها بعد النقطة

نفتح قوسي الدالة و نكتب 5 على سبيل المثال ، عندها سيقوم بقص أول 5 خانات و يطبع الباقي

يمكننا عن طريق إضافة فاصلة و رقم آخر إلى المثال السابق ، و عندها سيقوم بطباعة ما بين الخانة 5 و 11 ، و يقوم بحذف الباقي

 

ماذا لو أردت أن تحول كل أحرف الـ string إلى حروف كبيرة

عندها سنستخدم الدالة ToUpper بدلاً عن الدالة Substring ، و بعندها سيقوم بطباعة الخانات كلها مع تغيير حالة الحروف إلى حروف كبيرة

 

ماذا لو أردت استبدال خانة أو حرف بخانة أخرى ،

مثلا في النص السابق أريد استبدال خانة المسافة بخانة أخرى ، فعندها سنستخدم الدالة Replace ،

و هذه الدالة تحتاج إلى قيمتين ، فالأولى هي Old Character  و الثانية هي New Character

نكتب كل قيمة بين علامتي تنصيص ، و يفصل بين القيمتين بفاصلة

ندخل القيمة الأولى هي المسافة ، أما الثانية نجعلها الرمز –   ، عندها سنرى أن التطبيق استبدال المسافة بالرمز –

 

ماذا لو اردنا حذف جزء من الكلمة الموجودة ، فيمكن استخدام الدالة Remove  ، و لهذه الدالة أكثر من استخدام

فلو أدخلنا رقم واحد فقط ،  و ليكن الرقم 5 ، فسنلاحظ أنه أخذ أول 5 خانات و حذف الباقي

و لو قمنا بوضع قيمتين فسيقوم بحذف ما بين الخانة 5 و 11 و يطبع كل ما تبقى

 

استخدام الـ StringBuilder :

هناك قضية يجب أن ننوه لها ، فاستخدامك للـ string مكلف فعليا ، و نعني بذلك ، حاول قدر الإمكان التقليل من استخدامك للـ string

فاستخدامك له و تخزين Data  كبيرة داخله يحجز مساحات كبيرة في الذاكرة ، و هناك فرق شاسع بي تخزينك للـ integer  و تخزينك للـ string

لذلك حاول أن تكون حذراً و دقيقاً في استخدامه

 

لاحظ الآن سأقوم بمحاولة طباعة لـ string ضخم جداً ، و أقوم باستخدامه بطريقة غير مجدية

لاحظو هذه الطريقة في كتابة الحلقة for  ،

نكتب كلمة for و لا نكتب مسافة بعدها ، ثم نضغط Double Tab فسيقوم بوضع الهيكل الخاص بحلقة for

و هذه الميزة غير موجودة في كافة المحررات

بعد وضعه للهيكل الخاص يمكن التعديل عليه

 

سنشرح قضية هنا مهمة

لاحظو هنا القيم الموجودة قيمة integer  و في بعض الأحيان لا يقبل وضع قيمة int في متغير string

فمن الممكن تحويل أي متغير يمكن تحويله مهما كان نوعه  إلى string عن طريق الدالة ToString ،

الآن سيقوم البرنامج بعملية يأخذ القيمة الجديدة و وضعها في مكان معين ثم أخذ هذا المتغير مرة أخرى ،

و هذه العملية غير صحيحة كما تعلمنا ، فهي تقوم بعملية إضاعة

نحن هنانقوم بعملية 100 حلقة ، لكن تخيل لو كان لدينا 1000 حلقة أو مليون حلقة ، فسيكون مكلفاً جداً و سيقوم التطبيق باستهلاك مساحات كبيرة

لذلك لو كان لدينا string  كبير و يحتوي على أمور تجعلك بحاجة إلى القيام بعملية إضافة قيم له

فيفضل استخدام نوع جديد اسمه StringBuilder ، هذا النوع جداً مميز لاستخدام النصوص الكبيرة و عملية إضافة القيم إلى المتغير

لاحظو في المثال السابق كان يقوم بالإضافة بأسلوب غير مجدِ ، لذلك سنقوم بتحويل السابق إلى جمل ملاحظة

و مثلا هنا سنقوم بتعريف متغير من النوع StringBuilder باسم myString

 

لو قمنا بتطبيق البرنامج سيقوم تماما بعمل البرنامج السابق ، لكن قام بتقليل المساحة المستخدمة و لم يقم بوضعها في مكان و نقلها إلى مكان آخر ، بل قام بعمليات خاصة و مميزة للتقليل من حجم الذاكرة ،

 

إذا يفضل استخدام الـ StringBuilder إذا كان لدينا نص كبير يتم قراءته ، كملف تقوم بتخزين نصوص عليه ، و تحتاج لقراءته مرة أخرى ، يفضل وضعه بـ StringBuilder لأنه مخصص للنصوص الكبيرة

 

و إلى هنا نصل إلى نهاية درسنا :

تعلمنا طريقة استخدام الـ Back Slash Escabe Character

يمكنكم الاطلاع على  Standard Numeric Format String من شركة Microsoft

ستجدون بها جميع الخانات التي يمكن استخدامها

كان هذا درساً سريعة عن الـ string لتحصل على النتائج المطلوبة ، فقد استخدمنا الكثير من الـ Methods لنصل إلى النتيجة المطلوبة و لو حاولنا الوصول إلى النتيجة بدون هذه الدوال سيكون صعباً بل مستحيلاً

ملخص الدرس

مقدمة:

السلامُ عليكم ورحمةُ اللهِ وبركاته، وأهلاً بكمْ في الدرسِ السادس عشر من دروسِ سلسلةِ، تَعلُمِ البرمجةِ للمبتدئينَ كلياً بواسطةِ السي شارب، في هذا الدرس سنتعرف على كيفية التعامل بشكل أكبر مع النصوص، كونها شيء أساسي في كل المشاريع، سنتعلم كيف نقوم بقص جزء معين من جملة، وكيف نقوم بطباعة أرقام بهئية خاصة نقوم بتعريفها.

التعامل مع النصوص Strings :

لا يخلو تطبيق صغير أو كبير من إستخدام النصوص والتعامل معها، لذلك هناك عدد كبير من الدوال للنوع النصي String يمكنك معرفة المزيد عن الدوال التي تقوم بوظائف معينة، هنا شرح لبعضها :

رموز خاصة Escape Character : ويتم بإضافة \ وبعدها خانة مثل : n لسطر جديد ، ” لطباعة التنصيص داخل نص، \ لطباعته داخل نص، القائمة الكاملة للحروف هنا.
تهيئة النص string.Format : وذلك بإستخدام أرقام Index ويمكن إضافة تخصيص لها مثل : N لطباعة الأرقام بالفواصل ، P لطباعة قيمة مئوية، القائمة الكاملة هنا.
Substring : تقوم بعمل قص للنص.
ToUpper : تقوم بتحويل جميع الأحرف إلى أحرف كبيرة Capital letter .
Replace : إستبدال نص بنص آخر.

 

مصطلحات الدرس :

Compiler :

Back Slash :

Character :

Back Slash Escape Character :

index :

Format :

Percentage :

Substring :

ToUpper :

Replace :

StringBuilder :

Double Tab :

Standard Escape Format String :

 

تجد في الأسفل الأسطر البرمجية التي قمنا بكتابتها خلال شرح الدرس.

post

#15 الحلقة التكرارية While – البرمجة بواسطة #C

رمز فتح مرحلة هذا الدرس في تطبيق طورني : FEZ

تَعلُمُ البرمجةِ للمبتدئينَ كلياً بواسطةِ #C –  الحلقة التكرارية While

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

في درس اليوم بنتكلم عن الحلقة التكرارية While Loop

تأتي أهمية هذه الحلقة عندما لا يكون لديك حد معين لتنتهي دورات هذه الحلقة

أي أن دورها يكمن في تنفيذ أسطر معينة عدداً يمكن أن يكون غير معروف في البداية

 

نبدأ كما في العادة بإنشاء مشروع جديد بلغة سي شارب و اختيار Console App

كما تكلمنا عن المكان المخصص لكتابة الأسطر بين قوسي الدالة void Main  ،  و تكلمنا أيضاً عن إمكانية انشاء دوال خاصة ، و هذا الدرس سيكون ان شاء الله تركيزاً على استخدام الدوال لتنفيذ أسطر برمجية معينة

الآن في البداية سأقوم بكتابة كود ، يمكنكم اللحاق بي .

سأقوم باستدعاء هذه الدالة بكتابة اسمها و فتح و اغلاق أقواسها ، و وضع الفاصلة المنقوطة .

نشغل التطبيق … يقوم بطباعة جميع الخيارات الموجودة في لبرنامج و يطلب مني رقم من الأرقام الموجودة في البرنامج

لاحظوا أنني إن أدخلت أي رقم من الأرقام الثلاثة ، فإنه سوف يخرج من البرنامج .

و أنا لا اريد ذلك ، أريده أن يستمر في البرنامج إلى أن يقوم المستخدم بإدخال الرقم 3

لذلك سنقوم باستعمال الحلقة While  ليستمر في اظهار هذه الـ options ، إلى أن يقوم بكتابة الرقم 3

هنا سأقوم بتعريف متغير جديد من النوع bool ، و هو متغير جديد يحتوي على قيمتين إما True أو False

قمنا هنا بعملية إسناد للمتغير في نفس السطر .

اذا سأبدأ هنا بكتابة جملة While ، ماذا يحدث هنا

القيمة الأولية للمتغير displayMenu هي True

فهو يسأل في هذه الحلقة كالتالي :

طالما القيمة True سيقوم بتنفيذ الحلقة إلى ما لا نهاية ، و عندما يقوم بكسر الشرط سيخرج من الحلقة .

بتشغيل البرنامج و كتابة أي قيمة سيبقى ضمن البرنامج و يطبع الخيارات ذاتها .

بما أن الحلقة ستبقى تتكرر إلى أن تصبح القيمة خاطئة ، سأقوم بوضع شرط إذا قام بوضع رقم 3 ستصبح القيمة خاطئة و بالتالي سيخرج من الحلقة

لاحظو الدالة mainMenu من النوع void  أي أنها لا ترجع أي قيمة إلى مكان استدعائها

الآن سنقوم بتغييرها من void إلى bool ، فنلاحظ ظهور خط أحمر ، و الخطأ يقول:
“not all code paths return a value”
لأنه طالما أن هذه الدالة ليست void ، فيجب أن تقوم بإرجاع قيمة

فأنا هنا مبدئيا سأقوم بجعل البرنامج برجع قيمة False إذا قام بإدخال الرقم 3

و أيضاً سأقوم بتعبئة باقي الأماكن بإرجاع قيمة True إذا قام بإدخال باقي الأرقام

إذاً إذا ضغط الرقم 3 سيقوم بإرجاع False  ، هذا الـ False  هو القيمة الراجعة من الـ mainMenu أريد اسنادها للمتغير displayMenu

إذاً أي قيمة راجعة من الـ mainMenu سيقوم بإسنادها للمتغير displayMenu

و إذا كانت False  سيكون الشرط غير محقق و سيخرج من البرنامج

و عند تشغيل البرنامج ، و الضغط على أي قيمة غير الرقم 3 سيستمر البرنامج ، أما في حال ادخال الرقم 3  سيخرج من البرنامج

لاحظوا أن الموجود بين القوسين هنا while (displayMenu == true) هو Expression ، أي أنَّ القيمة النهائية هي True of False

و طالما أن هذا المتغير الموجود هنا يمكن أن يكون True or False  فلا داعي لكتابة == true

إذاً هنا نفذ القسم الثالث ، لذا سنكمل القسمين الأول و الثاني

سنقوم بكتابة Method  جديدة ، و لاحظوا أننا نقوم بكتابة الـ Methods في منطقة ما بين أقواس الـ Class ؛ و سنتكلم عن الـ Class لاحقاً إن شاء الله

هنا قمنا باستخدام شيء جديد و هو تحويل المتغير ، فقد تكلمنا سابقاً أن القيمة الراجعة من الدالة ReadLine  هي string

و إذا قمنا بتعريف متغير من النوع int فلا يمكن تحويل مدخلات الدالة ReadLine  إلى int لذلك قمنا باستعمال هذه الدالة لتقوم بعملية التحويل من string  إلى  int

بعد أن قمنا بتعريف متغير جديد ضمن الدالة الجديدة ، تطلب من المستخدم إدخال الرقم ، و تقوم بعد ذلك بعملية طباعة الأرقام من 1 إلى الرقم الذي قام المستخدم بإدخاله

نقوم باستدعاء الدالة التي قمنا بكتابتها إلى داخل جملة الشرط رقم 1

عند تشغيل التطبيق و ادخال 2 ، سيطلب من المستخدم إدخال رقم ثم يقوم بطباعة الأرقام كما ذكرنا

 

سنقوم الآن بكتابة Method جديدة للـ Guessing Game

في هذه الـ Method سأطلب من التطبيق إعطائي رقم عشوائي ، ثم أطلب من المستخدم القيام بتخمين الرقم الذي قام البرنامج باختياره

سنقوم بتعريف متغير جديد من النوع Random ، و سنعرف متغير جديد آخر من النوع int و سأطلب منه اختيار رقم عشوائي بين 1 و 7 مثلاً

و سأقوم بتعريف متغير من النوع bool باسم incorrect  و نسند إليه القيمة true

سأقوم بوضعه ضمن حلقة ، لكن سنتعرف هنا على نوع آخر من أنواع While Loop

 

الشكل الثاني للحلقة While Loop

في الـ  Methods  السابقة رأينا أن الحلقة تقوم بالتحقق من الشرط و إذا لم تتحقق فلا يتم تنفيذ الأسطر و يخرج مباشرة

هناك نوع آخر من أنواع While Loop و هو يقوم بتنفيذ الحلقة مرة واحدة على الأقل ثم يقوم بالتحقق من الشرط

الشكل الآخر يكتب كالتالي :

نكتب الكلمة do و نفتح قوس و ننتهي بقوس آخر من النوع {    }

و بعد القوس الأخير نكتب كلمة while و نكتب الشرط بين قوسين (      )

فنلاحظ أن الشكل الأول للحلقة يتم بكتابة while ثم نفتح قوساً و ننتهي بقوس ، أما الشكل الثاني فيتم كتابة كلمة do في  البداية و نكتب كلمة while  ثم الشرط بعد القوس الأخير

فبالتالي في  الشكل الأول يقوم بالتحقق من الشرط أولا ، أما في الشكل الثاني يتم التنفيذ لمرة واحدة ثم يتم التحقق من الشرط ، و بالتالي إن تحقق الشرط سيقوم بتنفيذ الحلقة مرة أخرى ، أما إن لم يتحقق فإننا بهذه الحال تأكدنا من تنفيذ الشر مرة واحدة على الأقل

نتابع كتابة الدالة ، فبعد أن يقوم بتلقي المعلومات من المستخدم نضع شرطاً إذا كانت القيمة المدخلة result مساوية لـ randomNumber

و نلاحظ هنا أنني سأقوم بعملية تحويل القيمة التي من النوع int  إلى text .

كيف يتم ذلك ؟

بعد كتابة أي دالة إذا قمت بكتابة نقطة سيكون لدينا ToString و هي الدالة التي تقوم بالتحويل من int  إلى string

نعود إلى الشرط الذي قمنا بكتابته فإن كانت القيمة محققة و النتيجة True سيقوم بإسناد قيمة False للخروج من الحلقة

أما إن لم تكن محققة ، فسيتم الاحتفاظ بالقيمة true  ليبقى في الحلقة و يقوم بتنفيذها مرة أخرى ، كما سيتم طباعة جملة Wrong !

و نلاحظ أنه لا داعي لإسناد قيمة True لأن المتغير incorrect في الأصل تم إسناد القيمة true  إليه كقيمة ابتدائية

و بهذه الحلقة سيبقى يسأل عن الرقم حتى يتسطيع المستخدم الوصول إلى التخمين الصحيح للرقم

نقوم الآن بعملية استدعاء للدالة في الأعلى و مباشرة نقوم بتشغيل البرنامج

ندخل الرقم 2 للدخول إلى لعبة التخمين
يطلب مني ادخال رقم بين 1 و 7

نجرب الإدخال ، و في حال إدخال رقم غير مساوي للرقم المطلوب سيتم عرض “Wrong ! ”

و عند ادخال الرقم الصحيح سيعود إلى القيمة الرئيسية بسبب أرجاع قيمة False  كما ذكرنا بالنسبة للحلقة

 

يمكننا أن نعطي للمستخدم إمكانية معرفة عدد  المرات التي قام بتجريبها قبل الوصول للإجابة الصحيحة

 

سنقوم بتعريف متغير جديد في الدالة باسم Guesses  من النوع int   و نعطيه القيمة 0 كقيمة ابتدائية و كل مرة يقوم بإعادة تنفيذ الحلقة سيقوم بزيادة 1 للتغير

في النهاية سنقوم بطباعة المتغير بعد تحقق الشرط و الخروج من الحلقة

لنتأكد من ذلك

نعم تم عرض عدد المرات و الرقم هو 4

الآن في كل مرة يقوم البرنامج بتكرار السؤال!

ماذا لو اردنا أن تكون الطباعة على صفحة جديدة ، أي يقوم بمسح المعلومات السابقة

لذلك لدينا الدالة :

;()Console.Clear

تقوم هذه الدالة بمسح المعلومات السابقة و بناء صفحة جديدة

لذلك كل مرة نقوم باختيار رقم سيقوم بعمل حذف للسابق

نستخدم الدالة في أكثر من مكان حسب الحاجة

و بتشغيل التطبيق نلاحظ أنه يقوم بحذف المعلومات السابقة و يبدأ بصفحة جديدة

نقوم بتجربة لعبة التخمين فنصل للرقم الصحيح و لكن لا نرى النتيجة … لماذا ؟
لأنه قام بعمل مسح للصفحة بشكل سريع

لذلك يمكن أن نقوم بإضافة الدالة ReadLine لنتمكن من مشاهدة التائج

بإمكاننا أن نقوم بعمليات لترتيب التطبيق مثل إضافة أسطر و إلى ما هنالك ، و هي أمور فنية و تجميلية

هذه كانت فكرة الـ While Loop و كيف نقوم باستخدامها عدد مرات غير معروف في البداية

 

ملخص الدرس :

السلامُ عليكم ورحمةُ اللهِ وبركاته، وأهلاً بكمْ في الدرسِ الخامس عشر من دروسِ سلسلةِ، تَعلُمِ البرمجةِ للمبتدئينَ كلياً بواسطةِ السي شارب، في هذا الدرس سنتعرف على كيف أنه يمكننا تنفيذ حلقة تكرارية من الأسطر البرمجية مجهولة العدد، بحيث تنتهي وتخرج من وسطها بمجرد تحقيق شرط معين

الحلقة التكرارية While Loop :

تختلف هذه الحلقة عن For Loop في أنها قد تكون مجهولة عدد التكرارات في البداية، ففي مثالنا في هذا الدرس، سنجعل الحاسوب يقوم بأخذ رقم عشوائي، ونطلب من المستخدم تخمينه، وسنبقى نعطيه فرصه إلى أن يجده، بالتالي نحنا لا نعلم من أي مرة سيجده، وهنا تأتي فائدة الحلقة التكرارية While Loop .

مصطلحات الدرس :

WHILE Loop :

bool :

Class :

Guessing Game :

Random :

incorrect :

ToString :

Console.Clear :

post

محاكاة حركة أمواج البحار في محرك Unity

 

مقدمة :

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

إعرف ميزانيتك قبل البدء :

عندما أتكلم هنا عن الميزانية، لا أقصد إطلاقًا النقود، وإن كانت جزء من الميزانية إلا أنها ليست كل شيء، فعندما تريد إنجاز أي شيء ( نتكلم هنا عن مجال الألعاب )، تحتاج إلى معرفة تفاصيل معينة مثل، كم من الوقت تجتاجه لإنجاز هذا الأمر، أيضاً هل يتوافق مع متطلبات مشرعك، فمثلاً يمكننا الإستعانة بمحاكاة متوفرة على المتجر ومناسبة، إلا أنها تفتقر للعمل بشكل سلس على متصفح الويب مثلاً, بمعنى آخر أنك لن تستطيع الإستفادة من تلك المحاكاة إن كان مشروعك على متصفح الويب، لذلك لا تضع الوقت بالحصول عليها وتجربتها إن كانت لا تتناسب مع منصتك أصلاً!
مسك، المشروع الحالي الذي أعمل عليه وأديره، تطلب مني محاكاة لبحر يحيط جزيرة، ليس هذا فحسب، بل تطلب أيضاً محاكاة حركة السفن التي يحملها هذا البحر، فللوهلة الأولى قمت إختصاراً للوقت بالذهاب إلى متجر Asset Store للبحث عن شيء يتناسب مع ما أريد، ووجدت العديد منها هذه الأداة :

للوهلة الأولى بدى لي أن هذا ما أريده،  لكن بعد البحث والقراءة عن هذه الأداة وجدت أنها لا تتناسب مع ميزانيتي ( الوقت + المنصة ) فمشروعي سيصدر على منصة Web GL وهذا ال Shader لا يدعها بشكل كلي، فضاع جزء من وقتي بلا فائدة!

الحل أبسط مما تتخيل أحياناً :

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

  • – قمت بوضع وجه Quad واحد وقمت بجعله بحجم كبير لكي يبدوا وكأنه البحر، أي قمت بجعل الـ Scale له 2000 كل كل محور.
  • – ثم قمت بوضع صورة لموج قابلة للتكرار Seamless .
  • – ثم قمت بكتابة أسطر برمجية تقوم بعمل تحريك لإكساء المجسم Texture Scrolling ، كما في الصورة التالية :

عند هذه النقطة، حصلت على البحر كما في الصورة التالية :

لكن هذا وحده لم يكفي بالغرض، فضفاف الجزيرة وإمتداد الرمل يجب أن يبدوا واضحاً لإعطاء مصداقية بتدرج العمق، وكان الحل بتحويل Shader المادة التي أستخدمها من Standard إلى Particle –> Multiply كما في الصورة التالية :

عند هذه النقطة، إنتهيت من البحر نفسه، لكن بقي المشكلة هي حركة الأجسام التي تطفو عليه، فالبحر هنا عبارة عن وجه واحد فقط Quad وليس فيه أي حساب للتضاريس Deformation لكي يتأثر بها مجسم السفينة!

حركة السفينة :

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

بهذه الطريقة حصلت على المطلوب تماماً، وكنت راضياً جداً عن النتيجة!

الخلاصة المستفادة :

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

 

أسامة ديب
مطور ألعاب

 

 

post

#14 الدوال Methods – البرمجة بواسطة #C

رمز فتح مرحلة هذا الدرس في تطبيق طورني : OXW

تَعلُمُ البرمجةِ للمبتدئينَ كلياً بواسطةِ #C –  الدوال Methods

 

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

درس اليوم ” الدوال الـ Method “

و هي من أساسيات البرمجة و هي التي أعطت للمطورين إمكانية أن يقوم بتنفيذ مشروعه دون أن يقوم بتكرار الأسطر البرمجية أكثر من مرة

سابقاً لم يكن هناك دوال و كان المطور مجبراً على كتابة أسطر برمجية متتالية ، فتجد أن البرنامج عبارة عن 1000 سطر على سبيل المثال ، كلها متتالية حيث ينفذ السطر الأول ثم الثاني فالثالث و هكذا ….. مما كان يجعل الأمر صعباً

و خصوصاً في حال وجود أي خطأ في البرنامج فيجب أن يقوم بتتبع للبرنامج ليصل إلى مكان الخطأ

 

كما تعلمنا في كل الدروس السابقة نقوم بإنشاء مشروع جديد و نختار Visual C# ثم Console Application و سنكتب اسم البرنامج هذه المرة ” Methods ”
و تكلمنا أنه يجب أن نقوم بالبدء بالكتابة بين قوسي الدالة void Main

لكن في هذا الدرس سنتعرف إلى طريقة جديدة و مفهوم جديد يمكننا بواسطته إنشاء دوال .

و الدالة يمكن شرحها بأنها قطعة برمجية  Block of Code تبدأ بقوس و تنتهي بقوس آخر ، و تحمل اسم , حيث يتم استدعاء هذا الاسم لتقوم بالعمل الخاص بها .

لاحظو الدالة الرئيسية void Main و هي الدالة التي يبدأ بها الـبرنامج

سنقوم الآن بكتابة دالة رئيسية و سنقوم بشرحها و شرح التركيبة الخاصة بها

هذه الدالة يمكن استخدامها و استدعاؤها في الدوال الأخرى كالتالي :

أخذ اسم الدالة (PrintMessage) ثم فتح القوس الخاص بها و اغلاقه و كتابة الفاصلة المنقوطة .

و لا ننسى أن نقوم بكتابة الدالة ReadLine

عند تشغيل التطبيق سيقوم بطباعة Hello World !

الفكرة من الدوال أنه يمكنك إضافة العديد من الأسطر البرمجية في وِحدة خاصة بها ، بحيث في حال الحاجة إلى تكرار الأسطر ، فيمكنك استدعاؤها عن طريق اسمها دون الحاجة لكتابة كافة الأسطر .

شرح الدالة

في البداية يجب أن تقوم بكتابة الدالة خارج الـ void Main  لأنه لا يمكن كتابة دالة داخل دالة

لذلك إذا أردت كتابة دالة فيجب كتابتها خارج الدوال الأخرى

الترتيب غير مهم هنا و هذا يعني أنه بإمكانك كتابتها قبل أو بعد الـ void Main

و عند الحاجة إليها أقوم بكتابة اسمها دون كتابة الأسطر البرمجية الموجودة بداخلها

 

فوائد الدوال :

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

(2) : عدم تكرار الأسطر البرمجية نفسها

(3) : تقوم بتنظيم المشروع

(4) : في حال حصول أي مشكلة يمكن تعديلها بشكل بسيط في مكان واحد دون تتبع التطبيق بشكل كامل

 

هذه القضايا سنتكلم عنها في الدروس القادمة و سنتحدث الآن عن الدالة void

 

 

الـ void هي نوع من أنواع البيانات أو أنواع الـ Data مثل integer  و  string

لكنها لا تعود بقيمة و سنتعرف عليها بعد قليل

يمكننا نقل السطر ;()Console.ReadLine إلى الدالة التي قمنا بإنشائها

 

هذا التطبيق يعد بسيطاً ، لذلك سنأخذ برنامجاً قمت بكتابته سابقاً ، و هو يحتوي على تكرار للاسطر البرمجية و سنقوم بإضافة الدوال  لتحسينه و ترتيبه بشكل أفضل

 

هذا البرنامج يسأل المستخدم عن اسمه و اسم عائلته ، ثم يسأل عن المدينة التي ولد فيها ، ثم يقوم بإظهار رسالة تحتوي على العناصر السابقة بشكل معكوس كما تعلمنا في الدرس السابق ، و ذلك عن طريق الدالة Array.Reverse

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

ثم يقوم بتعريف Array من النوع char  ثم يأمر بتحويلها إلى مصفوفة ثم يقوم بعملية عكس لهذه المصفوفة

إذا لدينا ثلاث أسئلة و لكل سؤال 4 عمليات

و بالتالي لدينا تقريباً 12 سطر

و في النهاية يقوم بتعريف متغير جديد باسم result

و يقوم باستخدام الحلقة foreach ليقوم بأخذ هذه الأحرف و يجمعها ليعطي هذه النتيجة

نلاحظ عند تشغيل التطبيق أنه أخذ كلمة كلمة و لم يعكس الجملة كاملة ، حيث قمت بإدخال Osama  ثم  Deep ثم amman

فأخذ الاسم الأول و قام بعكسه ، ثم أضاف مسافة قبل الاسم الثاني ثم تابع أخذ الاسم الثاني و المدينة ،

عندها قام بإعطاء النتيجة كالتالي

Result : amaso peed namma

لنرى كيف نكتب دالة توفر علينا هذا الكم من الكتابة ، فبدلاً من كتابة 16 سطر سنقوم بكتابة 4 اسطر فقط و استدعاء هذه الدالة

 

الآن نقوم بتعريف دالة جديدة

ثم نكتب التالي ضم قوسي الدالة {   }

كما في المثال التالي :

 

في البداية سنقوم بالتطبيق على الـ firstName فقط ، سنستدعي الدالة ليقوم بعرض الموجود داخلها .

المتغير الأول هو السؤال و المتغير الثاني هو ناتج المدخل

الآن سيقوم بطباعة السؤال و ثم يكون بعملية عكس للأحرف المدخلة في الجواب

حيث يقوم بتحويله لمجموعة من character  و اسنادها في متغير جديد ثم يقوم بعكسها باستخدام الدالة Array.Reverse

و في النهاية سيقوم بطباعة firstNameArray

الآن لدينا الجزء المتكرر في كل المراحل السابقة و قد أصبح ضمن الدالة التي قمنا بإنشائها

الآن نقوم بعملية استدعاء للدالة التي قمنا بإنشائها

عندها سيسأل عن الاسم الأول و يطلب إدخاله ، و سيأخذ القيمة من المستخدم و يدخلها في متغير نصي  و يتابع

عند تشغيل التطبيق سيسأل عن الاسم و عند ادخال osama  يقوم بطباعة osama لكن بالشكل المعكوس … أي  amaso

 

الآن لنلاحظ أن هذه الدالة هي من النوع void و تقوم بتنفيذ الاسطر الموجودة بدون ارجاع أي قيمة أخرى

لاحظوا أنه سيكون لدينا مشكلة إذا قمنا بكتابة هذه الدالة للاسم الثاني و اسم المدينة

المشكلة هي أنه إذا قمت باستدعاء اسم الدالة فعندها سيقوم بطباعة الاسم الأول لوحده ، و نحن لا نريد هذا

نحن نريد أن يقوم بإرجاع القيمة الناتجة و استخدامها لاحقا

 

فقد تكلمنا أن الـ void لا يرجع أي قيمة ، لكن بإمكاننا استبدال هذا النوع بـ string

أي أن هذه الدالة ستقوم بعمليات معينة ثم ستعيد نصاً إلى مكان استدعائها

 

بما أن هذه الدالة أصبحت من النوع string  و ليس void  فيجب أن ترجع قيمة و بالتالي ستحتوي على return لشيء ما في نهايتها

و القيمة التي نريد ارجاعها هي النص الموجود لدينا  فيصبح السطر الأخير :

;Return string.concat(firstNameArray)

عندها سيكون هذا السطر راجعاً من الدالة DisplayResult

أي أنني في الأعلى يمكنني أن أقوم بتعريف

;()string firstName = DisplayResult

و النوع الموجود قبل إشارة المساواة من النوع string وبالتالي DisplayResult ذات الأمر ، لأن الدالة الموجودة في الأسفل من النوع string و النتيجة الراجعة من النوع string

نقوم بتشغيل التطبيق لنتأكد من صحة المعلومات و نلاحظ أنني لا اريد أن أقوم بطباعة الناتج داخل الدالة الثانية بل سأقوم بطباعته في الدالة void

 

فعلا قام التطبيق بطباعة osama  بشكل معكوس

سنلاحظ بعد قليل أن هذه الدالة قامت باختصار كاف الاسطر السابقة

 

و نتذكر أن الدوال من الممكن أن تكون int , string أو أي نوع من أنواع البيانات و يمكن أن تكون دالة لا ترجع قيمة مثل void

الشرط الأساسي أنه إذا لم تكن من النوع void فيجب عليك أن تقوم بإرجاع قيمة و هذه الدالة قامت بعمليات معينة و قامت بإرجاع الناتج النهائي
يمكننا الحصول على القيمة المرجعة عن طريق وضعها على الجانب الأيمن لإشارة المساواة في السطر الذي قمنا به باستدعاء الدالة و سيتم تخزينها مباشرة في firstName

الآن أريد استخدام هذه الدالة ليس فقط لطباعة الاسم الأول
بل لطباعة الاسم الأول و الأخير و السؤال عن المدينة التي ولد فيها

إذا في الدالة يمكنك أن تقوم بإرسال قيمة
لذلك سنقوم بتعريف متغير جديد

عندما نقوم باستدعاء الدالة يجب أن نرسل قيمة يتم ارسالها إلى الدالة

 

لذلك سنقوم بحذف السؤال في الدالة و نجعله قادماً من مكان استدعائها

إذا سنأخذ المتغير question و نضعه بعد string  بين قوسي الدالة (  )

الناتج كالتالي

سنقوم باستدعاء الدالة و نرفق معها السؤال بين القوسين ، عندها سيأخذ السؤال و يقوم بطباعته مباشرة و يقوم بعمليات معينة و يقوم بإرجاع القيمة النهائية إلى هذا المكان

 

الآن قمنا بإرسال هذا النص إلى الدالة و قام بطباعته و استخدام القيمة المرسالة مع هذه الدالة

نقوم بتعريف متغير جديد اسمه lastName ، و سأسأله سؤال ” ما هو اسمك الأخير” و القيمة الراجعة من الدالة سيقوم بإسناده للمتغير lastName
ثم نسأله عن مكان الولادة

لاحظو أن هذه الثلاث أسطر هي فعليا 12 سطر
لنتأكد أن القيمة الراجعة صحيحة

ثم نقوم بطباعة الناتج النهائي

بتشغيل التطبيق سيسأل عن الاسم الأول و الأخير و المدينة ، و سيقوم بعرض ذات النتيجة التي عرضها في التجربة الأولى

في حال حدوث مشكلة لا يجب تتبع الأسطر كلها ، بل نقوم بتتبع أسطر الدالة القليلة
حيث استخدمناها لتقليل عدد الأسطر

 

نصل الآن لنهاية هذا الدرس ، ألقاك في الدرس التالي إن شاء الله

 

ملخص الدرس :

السلامُ عليكم ورحمةُ اللهِ وبركاته، وأهلاً بكمْ في الدرسِ الرابع عشر من دروسِ سلسلةِ، تَعلُمِ البرمجةِ للمبتدئينَ كلياً بواسطةِ السي شارب، في هذا الدرس سنتعرف على  الدوال Methods أو ما يسمى Function في لغات أخرى، والتي تعتبر العصب الرئيسي الذي يقوم عليه أي تطبيق ولا يخلو منها.

الدوال Methods :

يمكن تعريف الدالة على أنها قطعة برمجية Code Block تبدأ بجملة تعريفية بإسمها ونوعها سواء كانت نصية string أو رقمية int أو لا ترجع أي قيمة void أو أي نوع آخر. والدوال لها العديد من الميزات أهمها:
– تقليل عدد التكرارات الموجودة في التطبيق، وبالتالي قلة عدد الأسطر الإجمالي.
– تنظم المشروع، بحيث تكون الأسطر البرمجية الخاصة بعملية معينة في مكان واحد.
– سهولة إيجاد المشاكل المنطقية في حال وجودها لاحقاً.
و طريقة كتابة الدالة هكذا :
Method_Type Method_Name ()
}
{

خصائص الدوال :

كما ذكرنا قبل قليل، إن كانت الدالة غير النوع void ( لا ترجع أي قيمة)، أي أنها من النوع int أو string أو float أو أي نوع آخر، فيجب أن تقوم بإضافة سطر return value في نهايتها ويمكن الحصول على العائد من الدالة بعملية الإسناد، أيضاً يمكن إرسال قيم عند مناداة الدالة لإستخدامها داخل الدالة وهي ما تدعى arguments أو parameters ، وهي متغيرات يتم إستخدامها داخل الدالة للقيام بالمهمة الموكلة لها.

مصطلحات الدرس :

Methods :

Block of Code :

return :

float :

arguments :

parameters :

الأسطر البرمجية التي تم إستخدامها في الدرس :

post

#13 المصفوفات Arrays – البرمجة بواسطة #C

رمز فتح مرحلة هذا الدرس في تطبيق طورني : YIL

تَعلُمُ البرمجةِ للمبتدئينَ كلياً بواسطةِ #C –  المصفوفات Arrays

السلام عليكم و رحمة الله و بركاته , و أهلا بكم في درس جديد من دروس سلسلة تعلم البرمجة للمبتدئين كلياً بواسطة الـ #C

في درس اليوم سنتكلم إن شاء الله عن المصفوفات أو الـ Arrays

تعريف المصفوفات :

يمكن تعريفها على أنها وعاء يحتوي على قيم بداخلها , أو هي عبارة عن صندوق فواكه يحتوي على عدداً من التفاح على سبيل المثال , و كل تفاحة لها قيمة الخاصة  ، و الصندوق الحامل لها يسمى المصفوفة .

 

نذهب إلى File  ثم New ثم project و نتأكد من اختيار #Visual Cو نختار Console App
تكلمنا سابقاً أن المكان المخصص لكتابة الأكواد البرمجية هو بين قوسي الدالة void Main

كي لا نضيع الوقت قمت بكتابة هذه الاسطر سابقاً و سأقوم بلصقها هنا

لاحظو أنني قمت بتعريف خمسة متغيرات هنا ، و كل متغير يحتوي على قيمة معينة

نريد الآن أن نقوم بالبحث عن الرقم 16 ، عندها سأكون مجبراً على كتابة جمل شرطية if statement  لكل متغير لكي أحصل على القيمة و أقارنها بالقيمة المطلوبة

في البداية نسأل هل قيمة المتغير number1 تساوي 16

ثم ننتقل إلى الثاني … الثالث ……. الخامس و هكذا

في هذه الحالة سأكون مضطراً لكتابة كل المتغيرات و كتابة عدد كبير من جمل if statement

هنا يأتي دور المصفوفة Array

سأقوم مبدئيا بتحويل الجمل السابقة إلى جمل ملاحظات

يمكن تعريف الـ array كالتالي

;int[ ] myNumber = new int [5]

لاحظو في هذا السطر قمت بتعريف مصفوفة اسمها myNumber  من النوع integer و تحتوي على خمس قيم

قمنا بكتابة الأقواس المربعة بعد النوع مباشرةً

الآن أصبح عندي 5 عناصر أو خمس خانات استطيع التعامل معهم

كيف يمكنني أن أقوم بإدخال قيم إلى هذه العناصر ؟

يمكننا فعل ذلك كالتالي :

;myNumber[0] = 10
;myNumber[1] = 22
;myNumber[2] = 14
;myNumber[3] = 66
;myNumber[4] = 22

الخانة الموجودة بين القوسين [ ] تسمى index

لذلك عندما تريد استدعاء عنصر ضمن المصفوفة تضع اسم المصفوفة و رقمه بين الأقواس [  ] مع ملاحظة أن الخانة الأولى يجب أن تحمل الرقم 0

إذاً من خلال الأسطر السابقة قمت بإدخال قيم إلى العناصر الموجودة ضمن الـ Array

الآن ماذا لو أردت أن أقوم بعملية استدعاء للقيم ؟

سأقوم من خلال التالي بطباعة قيمة أحد العناصر في المصفوفة

;Console.WriteLine(myNumber[2] )

 و لا ننسى كتابة الدالة ReadLine لنتمكن من مشاهدة النتائج.

نقوم بتشغيل التطبيق و نلاحظ أن التطبيق قام بطباعة القيمة 14

طريقة ثانية

الآن هناك طريقة ثانية لتعريف المصفوفة و إدخال القيم بها مباشرةً .

;int [ ] myNumbes = new int [ ] {1, 5 , 3 , 4 , 66 , 55 }

و كما تكلمنا لو اردنا طباعة القيمة رقم 3 فسنكتب :

; Console.WriteLine(myNumber[2] )

 

هناك إمكانية لطباعة ” عدد العناصر الموجودة داخل المصفوفة “

عن طريق التالي :

;Console.WriteLine(myNumber.Length)

هنا قمنا بطلب أخذ الـ Length ، و هو كم عدد العناصر الموجودة ضمن المصفوفة

و لو قمنا بعمل تشغيل للتطبيق ، سنحصل على القيمة 6 ، و هو فعلاً عدد عناصر المصفوفة السابقة .

في الاسطر السابقة استعملنا النوع integer ، و بالمثل يمكننا استعمال أي نوع آخر

مثلا هنا أقوم بكتابة

;  string[] myStrings = new string[] { “Ahmad”, “Mohammad”, “Shady”, “Safaa” }

و بالمثل سنقوم بطباعة قيمة العنصر رقم 3

 

;Console.WriteLine(myStrings[2] )

و لاحظ أنه قام بطباعة شادي

 

تحدثنا في المحاضرة السابقة عن For Loop Statement  التي تقوم بعملية تكرار لأوامر معينة ، لاحظة الآن سأقوم باستخدامها لطباعة كل عناصر المصفوفة

و ذلك كالتالي :

 

لاحظو أنه قام بطباعة كل عنصر من عناصر المصفوفة و ذلك بناءً على الـى Length

لاحظو أن عدد العناصر في المصفوفة هو 4 و هذا يعني أن myStrings.Length يساوي 4

و لذلك عندما وصل إلى الرقم 3 لقيمة i  فهو فعلياً وصل إلى آخر عنصر في المصفوفة ، و عندما أصبحت i = 4 يقوم بالخروج من الحلقة و ذلك لأن 4 تساوي 4 و ليست أصغر منها طبقاً لشرط الحلقة و بالتالي بعد أن أصبح شرط الحلقة غير محقق قام بالخروج منها

حلقة foreach

هناك أيضاً حلقة يتم استخدامها بشكل كبير مع المصفوفات ، ألا و هي  foreach

شرح هذه الحلقة :

بعد إضافة foreach  نقوم بتعريف متغير من النوع الذي تم تعريف المصفوفة به
و هنا قمنا بتعربفه من النوع string  تبعاً لنوع المصفوفة myStrings و بالنسبة لاسم المتغير الجديد فهو اختياري لأننا سنقوم باستخدامه حصراً ضمن الاقواس {  }

ثم نقوم بإضافة الكلمة المحجوزة in ثثم اسم المصفوفة و ذلك بدون أقواس [  ]

عمل الحلقة :

في كل مرة سيقوم بأخذ أحد العناصر (على الترتيب) ثم يقوم بإسناده الى المتغير name و يقوم بطباعته

و لاحظ أننا لم نقم بإعطائه الـ index  الخاص بالعنصر و إنما طلبنا منه أن يقوم بجلب جميع العناصر الموجودة داخل المصفوفة

 

 

هناك أيضاً إمكانية للتعامل بشكل أكبر مع المصفوفات :

 

إذا كان لدي نص معين و أردت أن أقوم بطباعة هذا النص بالعكس ( عمليةReverse )

هناك نوع جديد من أنواع البيانات هو النوع char و تكلمنا سابقاً أنه يقبل حرفاً واحداً فقط

;’char x = ‘a

الآن لدينا التالي :

;!! string myWords = “i need to go to the hospital now

يمكنني  أن أحصل على مصفوفة من myWords عن طريق الجملة :

;()Char[ ] x = myWords.ToCharArray

من خلال هذا الجملة نقوم بفصل جميع الحروف الموجودة في النص و تحويلها إلى عناصر في المصفوفة

myWords.ToCharArray تقوم بالعودة بمصفوفة يتم اسنادها للمصفوفة x  من النوع char

و نلاحظ هنا أننا قمنا بكتابة char و ليس فقط Array في myWords.ToCharArray لأنني أريد تحويل جميع الخانات خانة خانة إلى النوع char

الآن لو قمت بوضع بكتابة الحلقة foreach كما في التالي :

لو قمت بتنفيذ التطبيق سيقوم بطباعة الجملة حرف حرف في كل سطر

و لعكس المصفوفة نقوم بكتابة التالي :

سنشاهد عند تنفيذ التطبيق أنه قام بطباعة الجملة بشكل معكوس على نفس السطر .

 

طبعاً المصفوفات لها استخدامات أكثر مما تم ذكره ، و الدروس القادمة ستكون كفيلة بصقل مهارتك باستخدام الـ Array

نصل الآن إلى نهاية هذا الدرس ، ألقاك في الدرس التالي إن شاء الله .

ملخص الدرس :

تعريف المصفوفات:

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

المصفوفة Array :

يمكن تشبيه المصفوفة أنا عبارة عن صندوق فاكهة يحتوي تفاح، حيث أن هناك عدد كبير من التفاح غير أنه غير متساوي في المواصفات، فهناك الكبير وهناك ذو الحلاوة أكثر وهناك ذو الحمرة أكثر، غير أنهم يتشاركون بصفه أنهم جميعاً من النوع الواحد ألا وهو التفاح، والمصفوفة يمكن أن تكون أي نوع من أنواع البيانات الموجودة بداخل لغة السي شارب، سواءاً كانت نصية أو رقمية أو حتى متجهات ثلاثية البعد.
ويتم حجز المصفوفة بكنابة نوعها ثم أقواس مربعة ثم إسم المصفوفة ثم إعطاءها رقم للعناصر التي ستكون بداخلها هكذا :
int[] myNumbers = new int[5];

أو كما في المثال التالي :

مصطلحات الدرس :

Arrays :

Length :

foreach :

 index  :

Zero Base :

Reverse :

char :

ToCharAray :