سلام استاد.
خیلی ممنون.
منظورم از Editor ، کدهایی که در کلاس های TransparentControlBitmapEditor و TransparentControlBitmapEditorForm نوشتم ، هست.
لازم نیست کنترل ها و کلا کمپوننت هایی که توشون new میکنم را dispose کنم؟
متوجه منظورتون شده بودم، نه اون شما اون شیء که هایی که در TransparentControlBitmapEditor و TransparentControlBitmapEditorForm میسازید رو هر بار که کنترل ساخته میشه که اجرا نمی کنید، میسپارید به Designer که ذخیره کنه و با کدی که Designer میسازه بازتولید میشه، Dispose کردنش رو هم میسپارید به Designer.
-------
و یه سئوالی که تعجب مرا برانگیخت اینه که دیزاینر ویژال استودیو ، همه ی کنترل ها و کمپوننت هایی که مینویسه (و قابل dispose کردن هستند) را فقط با متد Dispose ای که در Form1.Designer.cs ای که مینویسه به همراه کدِ
کد:
this.components = new System.ComponentModel.Container();
ای که درون متد InitializeComponent مینویسه ، متوجه میشه که چه کمپوننت هایی را میخواد dispose کنه؟!!
نه اون components ربطی به Dispose شدن کنترل های روی فرم نداره. کنترل ها خودشون میدونند باید فرزندانشون Dispose بشن.
فرم خودش یک کنترل ئه، داخل Dispose کنترل هم Dispose طوری نوشته شده که فرزندان و نوه و نتیجه هاش هم Dispose بشن.
پس Designer برای اینکه کنترل های داخل فرم Dispose بشن نیازی به کد نوشتن اضافی نداره و بصورت پیشفرض و بدون کد نویسی اینکار انجام میشه و از بابت Dispose شدن کنترل های روی فرم نگرانی نداره.
اما برای کمپوننت ها اینطور نیست، اون کدی که اضافه میکنه برای کنترل ها نیست، برای کمپوننت ها است، مثل Timer و BackgroundWorker و ... که والد ندارن که روی فرم قرار بگیرند.
کنترل ها که روی فرم قرار می گیرند، ولی کمپوننت هایی مثل Timer که پنجره و ظاهر ندارند روی فرم قرار نمی گیرند، والد ندارند. برای همین موقع Dispose شدن فرم باید لیستی ازشون داشته باشیم که Dispose بشن.
اون لیست همون components ئه. جزئی از یک مجموعه IContainer میشوند که بعدا بشه موقع Dispose کردنش بهشون دسترسی داشت.
برای همین فرم به اون متغیر components نیاز داره که کمپوننت های فرم به مجموعه اضافه بشن تا موقع Dispose شدن فرم لیست کمپوننت ها موجود باشه تا Dispose بشن.
الان در کد بالا وقتی شی ای از کلاس Container ساخت ، خوب ، بعدش ، توسط متد Add ، کنترلی را بهش اضافه نکرد.
کنترل ها به Container اضافه نمیشن، کمپوننت ها اضافه میشن.
پس سر آخر ، وقتی اون اورلود متد Dispose (درون کلاس Form1.Designer.cs) ، چجوری میفهمه که کدوم کمپوننت ها و کنترل ها را باید dispose کنه؟
طبق روال Control.Dispose رفتار میکنه. کدش رو هم که می توانید پیدا کنید و ببینید. البته فرم خودش به این متد روال های دیگری اضافه میکنه، مثل آیکون و منو ... که باید نابود بشن.
و سر آخر ، چرا در Program.cs ، بعد از کد Application.Run ، اون فرم ای که نمایش داد را dispose نمیکنه؟
چون پنجره ای که به Application.Run تحویل داده میشه Dispose نشده که در نمیاد، با اجرای Application.Run ئه Dispose هم میشه.
میتوانید با یک متغیر جایگزین اش کنید تا ببینید اون متغیر بعد از Application.Run مقدار IsDisposed اش true هست یا نه.
اگه dispose کردن ، به همین سادگی هست ، پس چرا ما برای dispose کردن ، list ای از IDisposable درست کنیم و هر بار که شیِ جدیدِ قابلی dispose کردنی ای را میسازیم ، اون شی را به این لیست اضافه میکنیم؟ خوب ، ما هم این روش اش را بریم ها.
متوجه نشدم که چه روشی مد نظرتونه که میگید بهتره، ولی Container که داره شبیه همون لیستی که پیشنهاد کردم عمل می کنه. اگه منظورتون این باشه که لیست نباشه، باید برای هر شیء یک متغیر مجزا در نظر بگیرید که یکی یکی Dispose میخواد و با for قابل خلاصه کردن نیست. بجاش لیست باشه، هم کد نویسی کمتری میخواد و هم جمع و جور تره.
من همیشه متد dispose کردن را با آزاد کردنِ کل حافظه ی managed مربوط به اون شی ، قاتی میکردم . فکر میکردم وقتی dispose میکنیم ، کنترل مون ناپدید میشه ، پس شبیه به gc عمل میکنه و همه ی منابع را از حافظه پاک میکنه . واسه ی همین ، همیشه تعجب میکردم که اگه gc هست ، پس dispose واسه چی هست .
الان یه کم بیشتر متوجه شدم . دات نت برای کنترل هاشون و کلا کمپوننت هاشون ، در بخشی از کدهاشون ، از api ویندوز استفاده میکنند . api ویندوز هم از زبان ++C استفاده میکنند که میدونیم unmanaged هستند . وقتی dispose میکنیم ، این منابع api های ویندوز (که unmanaged هستند) را از حافظه پاک میکنند.
درسته دیگه؟
بله. درسته. البته در Dispose برنامه نویس هر کار دلخواهی رو انجام میده، ممکنه کلاسی اصلا منبع Unmanaged نداشته باشه ولی برنامه نویس برای نابود شدنش کار خاصی در نظر بگیره.
مثلا بعضی کلاس ها از (Dispose(true استفاده می کنند که فرضا متغیر های NET. شون که حافظه Managed دارند هم null بشن که در ادامه آزاد بشن ولی حالت کلی اینه که Dispose منابع Unmanaged رو آزاد کنه.