آموزش سی شارپ - کار کردن با فایل ها

شاید برای خیلی از شما دوستان پیش آمده باشه که بخواهید اطلاعات مورد نظرتون را داخل فایل ها ذخیره و یا از فایلی بازیابی کنید. در این جلسه از آموزش می خواهم یک مثال در رابطه با کار با فایل ها در سی شارپ بنویسم.

در دات نت یک namespace به نام System.IO وجود داره که داخلش کلی کلاس مختلف برای کارکردن با فایل ها وجود دارد. ابتدا اجازه بدین در رابطه با مفهومی به نام Stream توضیح بدم. Stream در واقع به یک سلسله از بایت ها اشاره میشه. حالا شما می تونید خودتون یک Stream ایجاد کنید و یا اینکه از Stream های بوجود آمده توسط دیگران استفاده کنید. در System.IO یک کلاس abstract به نام Stream وجود دارد که کلاس های زیر از آن به ارث رفته اند. نکته مشترک بین این کلاس ها این است که تمامی آن ها در واقع مجموعه ای از بایت های کنار هم هستند که می توانند حاوی اطلاعات باشند. شکل زیر چند کلاس که از کلاس Stream به ارث رفته اند را نمایش می دهد:

FileStream: همانطور که از اسمش برمی آید این کلاس به سلسله بایت های کنار هم در که یک فایل قراردارند اشاره می کند. در این کلاس متد ها و خصوصیاتی وجود دارند که به شما کمک می کنند که با فایل ها کار کنید ، اطلاعات بخوانید ، بنویسید و ...

NetworkStream: این کلاس هم یک مدل Stream است که در شبکه تبادل می شه و متناسب با نیازمندی های شبکه متد ها و خصوصیات خاص خود را دارد.

MemoryStream: این کلاس هم به شما امکان می ده تا یک سری اطلاعات را در حافظه نگهداری کنید. معمولا وقتی می خواهیم که یک Stream تولید بشه ولی نمی خواهیم که روی شبکه و یا فایل ذخیره بشه از این کلاس استفاده می کنیم.

برای اینکه این مفاهیم را بهتر درک کنیم می خواهم یک مثال ایجاد کنم که با فایل های متنی کار می کنه. حتما همه شما نرم افزار notepad ویندوز را دیدید. مثال ما هم شبیه به notepad خواهد بود. برای اینکار از یک پروژه نوع ویندوز استفاده می کنم و در داخل فرم اصلی نرم افزارم یک TextBox قرار می دهم. خصوصیت Multiline را به true ست می کنم و خصوصیت Dock را Fill تنظیم می نمایم و در نهایت اسم کنترل را به txtContent ست می کنم. سپس یک منوی اصلی با عنوان "پرونده" و چهار زیر منو با عناوین "جدید" ، "باز کردن" , "ذخیره" و در نهایت "خروج" ایجاد می نمایم. 

پس از انجام مراحل فوق فرم اصلی شما باید به این ترتیب باشد:

حالا من به دو متغیر نیاز دارم. متغیر اول برای اینکه بدونم که در هر لحظه چه فایلی باز شده است (من مسیر فایلی که باز کردم را نگه می دارم) از جنس string و با نام currentFilePath نگه می دارم. وقتی که فایل جدید دارم مقدار این متغیر را به string.Empty یا همان "" ست می کنم. متغیر دوم ، برای این است که بدونم آیا فایلی رو که بازکردم تغییر دادم یا نه. این متغیر را از جنس bool و با اسم isDirty نگه می دارم. در صورتیکه این مقدار این متغیر به true ست شده باشه معنی اش اینه که کاربر از زمانی که فایل را باز کرده تغییری در آن ایجاد کرده است.

حالا روی منوی جدید دوبار کلیک می کنم تا متد Handler برای رویداد کلیک این منو آیتم ایجاد شود. در این متد من باید 3 کار اصلی در این متد انجام بدم:

1. اطلاعات موجود در TextBox فرم را پاک کنم.
2. متغیر currentFilePath را به string.Empty ست کنم. (با اینکار اعلام میکنم که یک فایل جدید دارم)
3. متغیر isDirty را به false ست کنم. (با اینکار اعلام می کنم که هنوز کاربر تعییری ایجاد نکرده است)

پس شما باید این سه خط کد را داشته باشید:

private void mnuFileNew_Click(object sender, EventArgs e)
{
  txtContent.Text = string.Empty;
  currentFilePath = string.Empty;
  isDirty = false;
}
برروی منوی "بازکردن" دوبار کلیک می کنم و داخل متد Handler مربوط به رویداد کلیک کد زیر را می نویسم.
در خطا اول این کد یک شیء از جنس OpenFileDialog ایجاد می کنم. این شیء برای ایجاد پنجره انتخاب فایل استفاده خواهد شد. این پنجره امکان انتخاب کردن انواع فایل ها را داره ولی من می خواهم که فقط فایل های با پسوند txt را انتخاب نمایم. برای همین منظور در خط دوم این کد با استفاده از خصوصیت Filter مقدار مورد نظرم را به صورت یک string وارد می کنم. در خط سوم با استفاده از متد ShowDialog منتظر می مانم که کاربر فایل مورد نظرش را انتخاب نماید. در صورتیکه کاربر بر روی گزینه Cancel کلیک کند از این متد خارج خواهم شد ولی غیر این صورت فایل را با استفاده از خطوط بعدی باز کرده و اطلاعات آن را بر روی TextBox موجود در صفحه نمایش می دهم. ضمنا مسیر فایل باز شده را در متغیر currentFilePath را ست می کنم و متغیر isDirty را به false مشخص میکنم.

حالا باید فایل مورد نظرم را باز کنم و محتویات آن را خوانده و درون TextBox وارد نمایم تا کاربر بتواند متحویات آن را ویرایش نماید. برای اینکار باید یک شی از جنس FileStream ایجاد کنم. متد سازنده (Constructor) این کلاس دارای چندین ورژن مختلف با ورودی های مختلف می باشد. من از ورژنی استفاده می کنم که مسیر فایل و مقداری از جنس FileMode را به عنوان ورودی از من می گیرد. مقدار مسیر فایل را از خصوصیت FileName شی opf و مقدار FileMode را به Open (برای بازکردن فایل) پاس می کنم.

سپس یک شیء از جنس StreamReader که وظیفه خواندن اطلاعات موجود در یک Stream را دارد ، ایجاد می کنم. در متد سازنده این کلاس شیء FileStream خود را پاس می کنم تا مشخص کنم که قصد دارم محتویات این Stream را بخوانم. در کلاس StreamReader متدهای مختلفی برای خواندن محتویات وجود دارد که من از متد ReadToEnd برای خواندن کلیه محتویات تا انتهای این فایل استفاده کرده ام. این متد دارای خروجی از نوع String می باشد. حالا خروجی این متد را داخل TextBox موجود در صفحه قرار داده و خصوصیت isDirty را به false و خصوصیت currentFilePath را به مسیر فایل باز شده ست می کنم:

private void mnuFileOpen_Click(object sender, EventArgs e)
{
    OpenFileDialog opf = new OpenFileDialog();
    opf.Filter = "Text Files (*.*)|*.txt";
    if(opf.ShowDialog() == DialogResult.OK)
    {
        FileStream selectedFile = new FileStream(opf.FileName, FileMode.Open);
        StreamReader reader = new StreamReader(selectedFile);
        txtContent.Text = reader.ReadToEnd();
        reader.Close();
        isDirty = false;
        currentFilePath = opf.FileName;
    }
}
اگر مثال خود را تا اینجا تست کنید شما می توانید محتویات یک فایل Text را خوانده و برای کاربران نمایش دهید. در قسمت بعدی این مثال را ادامه خواهیم داد.

فیلم های آموزشی - Caching in ASP .NET - قسمت چهارم

قسمت سوم از سری ویدئوهای آموزش Caching در ASP .NET است. در این قسمت در رابطه با SQL Cache Dependency را بررسی می کنم.

نمایش ویدئو آموزشی Caching در ASP .NET - قسمت چهارم

دانلود مثال ویدئو آموزشی Caching در ASP .NE - قسمت چهارم


همانطور که در این ویدئو خدمتتون عرض کردم ، در ویدئو بعدی نکات باقی مانده از این مبحث را بررسی خواهم کرد و انتهای آن هم به سوالاتی که در این حوزه از طرف شما مطرح بشه پاسخ خواهم گغت. پس منتظر سوالات ،  انتقادات و پیشنهادات هستم.

فیلم های آموزشی - Caching in ASP .NET - قسمت سوم

قسمت سوم از سری ویدئوهای آموزش Caching در ASP .NET است. در این قسمت در رابطه با Cache Dependency نوع File بررسی می کنم.امیدوارم که مفید باشه.

در این ویدئو جدید ، بحث ASP .NET Caching را ادامه می دهیم:

نمایش ویدئو آموزشی Caching در ASP .NET - قسمت سوم

دانلود مثال ویدئو آموزشی Caching در ASP .NE - قسمت سوم

منتظر انتقادات و پیشنهادات هستم.

نسخه جدید مطالب آموزشی

برای دوستانی که با فایل های Pdf راحت تر هستند و تمایل دارند که مطالب آموزشی این وبلاگ را به صورت فایل Pdf داشته باشند ، یک نسخه بروز رسانی شده از مطالب وبلاگم که حدود 105 صفحه A4 شده است ، را آماده کردم.

برای دانلود این فایل می توانید از طریق لینک زیر اقدام نمائید.

http://www.tabatabaei.info/csharpsamples/CSharpTutorial.pdf


فراموش نکنید که نظرات شما ، به بهبود این مطالب کمک میکنه!
موفق باشید.

آموزش سي شارپ - قسمت سي و هفتم

رويداد ها و آرگيومنت هاي خاص - Event and Custom EventArgs

بسیاري از رويداد ها در هنگام وقوع داراي جزئياتي مي باشند. به عنوان مثال رويداد MouseMouse داراي اطلاعات همچون محل Cursor موس مي باشد يا در رويداد KeyDown کليدي که تايپ شده است از اطلاعات خاص اين رويداد است. ايجاد رويداد ها و پاس کردن اطلاعات خاص آن رويداد ها توسط کلاس هايي که از کلاس پايه اي به نام EventArgs به ارث رفته اند ، اعلام مي گردد.

براي بررسي اين موضوع از يک مثال استفاده مي کنيم. فرض کنيد که در مثال قبلي مي خواهيد که در موقع بروز رويداد LowAmount امکان جلوگيري از خريدي در حال وقوع را داشته باشيم. پس شما بايد يک متغيير boolean در پارامتر هاي رويدادتان به نام Cancel تعريف کنيد که در صورتي که توسط متد EventHandler به True ست شده باشد بايد از خريد جلوگيري نمائيد.

براي اجراء اين موضوع يک کلاس به نام LowAmountEventArgs تعريف مي کنيم (اين کلاس از کلاس EventArgs به ارث مي رود) و در آن يک متغيير به نام Cancel از جنس bool تعريف مي کنم:



سپس delegate مربوط به رويداد را به صورت زير تغيير مي دهم:



همچنين در زمان رويداد يک شيء از جنس LowAmountEventArgs ايجاد مي کنم:



حالا در زمان رويداد اين امکان وجود دارد که کاربر از ثبت اين برداشت از انبار جلوگيري کند. براي اين کار کافيست که کاربر شما در event handler مربوط به استفاده از متغيير موجود مقدار Cancel را به True ست کند.



نمونه هاي بسياري از اين نوع رفتار ها در دات نت وجود دارد ، به عنوان مثال در کلاس Form در Windows Application وقتي درخواست بسته شدن فرم از طرف کاربر ارسال مي شود ، يک رويداد به نام FormClosing رخ مي دهد ، در صورتيکه شما يک EventHandler براي اين رويداد بنويسيد مي توانيد با ست کردن متغيير Cancel در کلاس FormClosingEventArgs مي توانيد مانع از بسته شدن فرم شويد.

دانلود مثال اين پست

آموزش سي شارپ - قسمت سي و ششم

رويداد ها در سي شارپ - Events in CSharp
اغلب نرم افزار هايي که توليد مي شوند ساختاري Event Driven1 دارند. به عنوان مثال شما يک فرم ايجاد مي کنيد و کاربر با پر کردن اطلاعات فرم و در نهايت کليک بر روي گزينه ذخيره فرم اطلاعاتي مورد نظر را ذخيره مي نمايد.
پر کردن فرم ، کليک بر روي گزينه Save و ... همگي رويداد هايي هستند که از طرف کاربر شما ارجاع مي شود و چک کردن اطلاعات و ذخيره کردن اطلاعات و ... هم پاسخ (عکس العمل) هاي شما به آن رويداد ها.

براي توليد و استفاده يک رويداد در سي شارپ 7 مرحله پياده سازي وجود دارد. 5 مرحله اول براي توليد رويداد (Event Raise) و 2 مرحله آخر براي پاسخ به رويداد (Event Handler) مي باشد.

در بررسي رويداد ها با يک مثال ساده شروع مي کنيم. يک انبار را در نظر بگيريد. در اين انبار وقتي تعداد يک کالا به صفر مي رسد يک رويداد بايد اعلام شود و در نتيجه آن رويداد مسئول انبار درخواست خريد چند آيتم از آن کالا را صادر خواهد کرد. کلاس انبار را به صورت زير تعريف ميکنم. براي ثبت محصول از متد AddProduct و براي دريافت کالا از متد GetProduct استفاده مي شود. در صورتيکه تعداد کالا به صفر برسد ، رويداد مورد نظر بايد اعلام شود.

براي تعريف رويداد ، ابتدا يک delegate تعريف مي کنيم (مرحله اول):



دقت کنيد که delegate هايي که به منظور توليد Event ها ايجاد مي شوند همواره داراي دو پارامتر مي باشند. پارامتر اول از نوع object که در واقع شيء است که رويداد بر روي آن اتفاق مي افتد. پارامتر دوم از نوع EventArgs یا کلاس هاي که از آن به ارث رفته باشد. پارامتر دوم در واقع اطلاعات يا آرگومان هاي رويداد مي باشد. 2 
در مرحله دوم يک event در کلاس Warehouse تعريف مي کنيم (مرحل دوم):



در مرحله بعدي يک متد protected به نام OnLowAmount تعريف مي کنيم (مرحله چهارم3)



و سپس در زمان مناسب (موقعي که تعداد کالا به صفر برسد) رويداد را با استفاده از متد protected مرحله قبل اعلام مي کنيم (مرحله پنجم):




سپس شروع به استفاده از اين کلاس خواهم کرد:



همانطور که مي بينيد در اين کلاس رويداد LowAmount به صورت يک Event (با شکلي شبيه علامت برق) مشخص شده است.

مرحله بعدي ايجاد يک متد است که با ساختار delegate رويداد مورد نظر مطابقت داشته باشد (مرحله ششم):



و در نهايـت وصل کردن اين متد (مرحله ششم) به رويداد با استفاده از =+ مي باشد. (مرحله هفتم):



دقت فرمائيد که در صورتيکه تمايل داشته باشيد مي توانيد بيش از يک متد را داخل رويداد خود به عنوان EventHandler قرار دهيد:



  1. http://en.wikipedia.org/wiki/Event-driven_programming
2. به عنوان مثال در رويداد KeyDown بر روي کلاس Form از کلاس KeyٍEventArgs استفاده شده است.
3. در اين مثال نيازي به وجود مرحله سوم نمي باشد.

دانلود مثال اين قسمت
ادامه دارد...

آموزش سي شارپ - قسمت سي و پنجم

در مثال قبلی در رابطه با چهار مرحله توليد و استفاده يک Delegate صحبت کرديم. دقت کنيد که معمولا مراحل توليد يک delegate کنار همديگر استفاده نمي شود. و اين مراحل بين چندين کلاس پخش مي شود تا استفاده اصلي آن مشخص شود.

اجازه بدين با يک مثال ادامه بديم:

يک بانک را در نظر بگيريد. مشريان اين بانک داراي اعتبار مشخصي مي باشند. در هنگام خريد اين اعتبار کمتر و کمتر خواهد شد. اين بانک داراي n بازرس است که در سطح شعب مختلف فعاليت مي کنند. بازرسان بانک وظيفه پيگيري وضعيت اين مشتري را دارند. پس وقتي خريد مشتري از اعتبارش بيشتر مي شود بايد اطلاعات مشتري به تمامي بارزسان اعلام شود تا پيگيري هاي لازم توسط نزديک ترين بازرس انجام شود.

خوب پس من يک کلاس خواهم داشت به نام Customer و يک کلاس هم به نام Agent:



همانطور که مي بينيد کلاس Customer داراي يک متد به نام Buy است که از اين طريق خريد انجام مي شود. نکته مهم اين است که بايد کدي بنويسيم که وقتي يک مشتري خريد مي کند تمام بازرسان متوجه خريد بيش از اعتبار وي شوند.



در کلاس Agent يک ArrayList براي ثبت فعاليت هاي هر يک از بازرسان در نظر گرفته شده است که براي ثبت پيگيري جديد بايد از متد AddTask استفاده شود. پس ما بايد به طريقي AddTask تمامي بازرسان را همزمان و در متد Buy کلاس Customer فراخواني کنيم.

براي انجام اين موضوع من يک Delegate متناسب با متد AddTask ايجاد مي کنم (مرحله اول).



حالا در کلاس Agent يک متغيير static (براي همه بازرسان) از جنس آن delegate ايجاد مي کنم. (مرحله دوم)
سپس در Constructor کلاس Agent متد AddTask هر يک از بازرسان را در delegate ثبت مي کنم. (مرحله سوم).

در نهايت موقعي که اعتبار مشتري من منفي مي شود delegate static را فراخواني مي کنم. در نتيجه به تمامي بازرسان يک وظيفه جديد اضافه خواهد شد.


و حالا کافيست چند شيء از هر کدام از کلاس ها بسازم و شروع به تست کنم:



و در نتيجه:


اين مثال را مرور کنيد. مسلما براي دوستاني که تازه با سي شارپ آشنا شده اند خيلي سنگين خواهد بود. اصلا مهم نيست کافيه که توي ذهنتون چند باري مرورش کنيد. به نظر من delegate سنگين ترين بحث سي شارپ است. پس اصلا به خودتون شک نکنيد!

بارگزاري مثال

ادامه دارد....

آموزش سي شارپ - قسمت سي و چهارم

Delegates in CSharp
بعد از بررسی اينترفيس ها بايد به بررسي دليگيت ها بپردازيم. براي اين بررسي ابتدا من يک تعريف از Delegate خواهم گفت. سپس به روش ايجاد (Syntax) دليگيت ها مي بپردازم و در نهايت به دلايل استفاده یا مثال هاي آن خواهم پرداخت. لطفا سعي کنيد که در بررسي delegate ها کمي حوصله کنيد و با دقت مطالب را مطالعه کنيد.

delegate چيست؟
delegate ها type هايي هستند که اشياء آن ها مي توانند متد هاي کلاس هاي ديگر و متد هاي اشياء ديگر را فرخواني کنند. در واقع يک شيء از يک دليگيت براي فراخواني متد هاي کلاس ها و اشياء ديگر ايجاد مي شود.

چگونه يک delegate تعريف کنيم؟
من براي ايجاد يک delegate چهار مرحله در نظر مي گيرم.
  1. تعريف delegate یا Delegate Definition
  2. ايجاد reference از delegate یا Delegate Declaration
  3. ايجاد شيء یا Delegate Initialization
  4. فرخواني یا Calling
اجازه بدين اين مراحل را با يک مثال ساده بررسي کنيم.
مرحله اول بايد در namespace نوشته شود. همانند يک کلاس يا type هاي ديگر. وقتي مي خواهيم يک delegate را بنويسيم بايد بدانيم که اين delegate براي فراخواني چه متدهايي نوشته شده است.

همان طور که در تصوير مي بينيد من يک delegate را در فضاي namespace تعريف کرده ام. با توجه به کد نوشته شده ، اين delegate امکان فرخواني متد هايي را که خروجي ندارند (void) و همينطور هيچ پارامتري هم ندارند ، دارد.  استفاده از کلمه CallBack در انتهاي نام delegate ها پيشنهاد مي شود.

حالا بايد يک reference از آن delegate ايجاد کنيم:


در مرحله سوم بايد اين reference را new کنيم:



در اين مرحله بايد شما نام يک متد و فقط نامش را به عنوان پارامتر به constructor اين delegate پاس دهيد. توجه کنيد که تمامي delegate ها داراي Constructorی با يک پارامتر مي باشند که اسم يک متد خواهد بود. متدي که پاس مي شود بايد دقيقا ساختاري شبيه به ساختار تعريف شده delegate شما (مرحله 1) داشته باشد.

مرحله آخر فراخواني delegate است:



وقتي يک شيء از يک delegate را با استفاده از () فراخواني مي کنيد در واقع متدي که داخل آن delegate تعريف شده است را فراخواني مي کنيد.

نکته مهم اين است که شما مي توانيد بيش از يک متد (با ساختار شبيه به هم) را داخل يک delegate قرار دهيد. براي اين کار به جاي استفاده از = موقع new کردن از =+ استفاده خواهيم کرد. وقتي اين delegate را فراخواني مي کنيد تمامي آن ها به ترتيب فراخواني خواهند شد.



دانلود مثال
ادامه دارد...

آموزش سي شارپ - قسمت سي و سوم

در مثال قبلي با پياده سازي کلاس EmpCustomer به مقصود خود رسيديم و در واقع مي توانستيم که اشيايي از اين نوع را هم به ICustomer و هم به IEmployee نسبت دهيم. حالا به کد زير دقت کنيد:



همانطور که مي بينيد من 3 شيء جديد ايجاد کرده ام. 2 تا Employee و يک EmpCustomer و آنها را به عنوان کارمند در ليست کارمندان شرکت اضافه نموده ام. و همينطور 2 شيء ديگر که از نوع Customer هستند. و به همراه شيء قبلي که از جنس EmpCustomer بود به ليست مشتريان شرکت اضافه کرده ام. حالا اگر از شيء شرکت متد هاي چاپ ليست مشتريان و چاپ ليست کارمندان را فراخواني کنم نتيجه زير را خواهيم ديد.



اين نتيجه در واقع نتيجه درستي است چرا که من 3 مشتري و 3 کارمند دارم. اما نکته اي که وجود دارد اين است که شيء EmpCustomer من در موقع نمايش اطلاعات خود ، با ما بقي اشياء من متفاوت است. يعني وقتي در ليست کارمندان نمايش داده مي شود تفاوت آن با بقيه کارمند و در ليست مشتريان با بقيه مشتريان مشهود است. اما من مي خواهم که در هر دو حالت کاملا شبيه به اين دو نوع باشد و رفتاري مشابه بقيه داشته باشد. در نتيجه من بايد از Explicit Interface Implementation استفاده کنم.

Explicit Interface Implementation
اين روش موقعي استفاده مي شود که شما مي خواهيد رفتار يک شيء را بسته به نوع reference آن تعيين کنيد. يعني وقتي به يک شيء از جنس EmpCustomer از دیدگاه ICustomer نگاه مي کنيد رفتاري شبیه مابقي ICustomer ها داشته باشد و وقتي از دید IEmployee نگاه مي کنيد رفتاري شبيه به مابقي IEmployee ها داشته باشد و در حالتي که از ديد EmpCustomer نگاه مي کنيد رفتار خاص ديگر داشت باشد. در مثال ما شما بايد متد Print را سه مرتبه پیاده سازي کنيد. به اين کد دقت کنيد:



همانطور که مي بينيد در پياده سازي هاي دوم و سوم ابتدا نام interface و سپس دقيقا اسم متد را به همان ترتيب که در interface ها نوشته شده است و بدون access modifier مي نويسيم. در پياده سازي متد نيز کاملا شبيه به Employee و Customer عمل خواهيم کرد. در نتيجه اگر مثال قبلي را دوباره اجرا کنيد خروجي به شکل زير خواهيد داشت.



بارگزاري مثال

ادامه دارد...

آموزش سي شارپ - قسمت سي و دوم

اينترفيس براي توارث چندگانه - Interface for Multiple Inheritance
در پاره اي از مواقع , به اين نتيجه مي رسيم که يک موجوديت در نرم افزار شما بايد از دو يا چند موجوديت ديگر به ارث برود. اما همانطور که قبلا هم اشاره کرده بودم در سي شارپ توارث چندگانه وجود ندارد پس شما نمي توانيد از چند کلاس همزمان به ارث برويد. راه حل اين سناريو ها استفاده از اينترفيس ها براي پياده سازي توارث چندگانه مي باشد. نکته اي که وجود دارد اين است که استفاده از اين روش باعث کم تر شدن کد نويسي شما نخواهد شد.

فرض بفرمائيد که در طراحي يک سيستم براي يک شرکت توليد دو موجوديت "مشتري" و "کارمند" طراحي شده اند. هر مشتري داراي اطلاعاتي نظير نام و مبلغ اعتبار و یک متد برای خرید و يک متد براي نمايش اطلاعاتش می باشد.  هر کارمند نيز داراي اطلاعاتي نظير نام و حقوق و یک متد برای نمايش اطلاعاتش می باشد. حالا شما به این نتيجه رسيده ايد که يکسري از کارمندان شرکت از شرکت خريد نيز انجام مي دهند يعني در واقع مشتري هم هستند. به همين دلیل تصميم گرفته ايد که يک کلاس به نام EmpCustomer ايجاد کنيد که هم از مشتري به ارث رفته باشد و هم از کارمند.

خوب همانطور که گفتم اجراي اين سناريو با توجه به اينکه امکان به ارث رفتن از دو يا چند کلاس به طور همزمان وجود ندارد شما بايد از يک روش ديگر يعني استفاده از interface ها اقدام کنيد.

پياده سازي توارث چندگانه با استفاده از اينترفيس ها

همانطور که قبلا اشاره کرديم يک کلاس توانايي به ارث رفتن از يک کلاس و چندين اينترفيس را دارا مي باشد. براي همين منظور من دو اينترفيس به نام هاي ICustomer و IEmployee ايجاد مي کنم:



سپس دو کلاس خود يعني Employee و Customer را از اينترفيس هاي متناظرشان به ارث مي برم و پياده سازي مي کنم:





حالا کافيست کلاس سوم را از ايجاد و از هر دو اين اينترفيس ها به ارث مي بريم:



همين طور که در تصوير مي بينيد در Print به جاي عبارت Employee یا Customer عبارت EmpCustomer چاپ خواهد شد.

!! در اين روش قصد ما اصلا کمتر نوشتن کد نمي باشد بلکه فقط پياده سازي توارث چندگانه مي باشد.

!! توجه داشته باشيد که وقتي يک کلاس از دو یا چند اينترفيس به ارث مي رود که داراي اطلاعات مشترکي هستند (مثل Name و Print در اين مثال) يکبار پياده سازي آن کافي است.

حالا کلاس Company را ايجاد مي کنم و به جاي اينکه يک آرايه از جنس Customer براي مشتريان و يک آرايه از جنس Employee براي کارمندان در نظر بگيرم آرايه اي از ICustomer براي مشتريان و آرايه اي از IEmployee براي کارمندان در نظر خواهم گرفت.



همانطور که در تصوير بالا مشاهده مي کنيد يک متد براي درج مشتريان به نام AddCustomer در نظر گرفته ام و نوع ورودي آن را از جنس ICustomer در نظر گرفته ام. همين روش براي متد AddEmployee هم با IEmployee انجام داده ام. در نتيجه شما مي توانيد اشيايي از جنس Employee و EmpCustomer را در ليست کارمندان و اشيايي از جنس Customer و EmpCustomer را در ليست مشتريان قرار دهيد.

اين مثال ادامه دارد...