گفتگو هایی در باب سی شارپ

the_king

مدیرکل انجمن
خیلی ممنون استاد .
یه چیزی میگم ، فقط بهم نخندید.
اینکه دیزاینر وقتی میخواد کدی را اجرا کنه ، ممکنه یه خط را اجرا کنه و یه خط یا یه کد دیگه را اجرا نکنه؟
من توی این مدت که دارم با کدنویسی دیزاینر کار میکنم ، چیزهای بسیار عجیبی میبینم . چندین بار برام پیش اومد که کدهایی (اعم از MessageBox.Show و چیزهای دیگه) را اجرا نمیکنه . در واقع بهتره بگم که مثلا یه تابع (ای که قطعا مطمئنم فراخونی اش کردم رو فراخونی نمیکنه) یا یه رویدادی که قطعا مطمئنم زمانش رسید را اجرا نمیکنه .
مثلا توی رویداد کلیک 3 تا دکمه (که رویداد کلیک هر چند تاشون به یه رویداد یا متد متصل بود) ، هر چی کلیک میکردم ، کدها اجرا نمیشدن . تعجب کردم که شاید کلیک شون را متصل نکردم یا نام شی را اشتباه نوشتم و ... . رفتم دقیق چک کردم ، دیدم رویداد کلیک دقیق هر 3 دکمه ، به دقیقا همون متدم متصل بودن .
بعد ویژال استودیو رو بستم و دوباره باز کردم (بدون اینکه چیزی و کدی را تغییر داده باشم) ، دیدم این بار درست کار میکنه. اما یه مشکل .
Designer مشکلی با اجرا کردن کد ها نداره، اما وقتی به دلیل ایراد در کدتون یک بخشی قابل اجرا نباشه، روتین ناقص اجرا میشن و ممکنه پیام خطایی هم نمایش داده نشه.
کلا همیشه مشکل رو باید در کد خودتون جستجو کنید، اگر اجرای عجیب و غریبی داشته باشه بخاطر اشتباهی در کد نویسی شما است، Designer رو متهم نکنید.

اما قضیه ی ثبت کردن مگه چجوری هه؟ الان ما این همه پروپرتی هاش (در پست های قبل ، مثل پروپرتی DefautBitmap و ... که معلوم شد تا فقط اگه شی جدیدی به TransparentControlBitmap بدیم را ثبت میکنه) را تغییر میدادیم ، چرا ثبت نمیکرد؟
من گفتم استاد ، از همون شی ، هر وقت دلش میخواست ثبت میکرد . روال مشخصی برای ثبت کردن نداره.
باز ناچارم صحبت های قبلی رو تکرار کنم، مشخصه های یک شیء هر چقدر که تغییر کنه، شیء همچنان همون شیء ئه و تغییری نکرده. Designer هم ملاکش برای ذخیره کردن TransparentControlBitmap مقدار مشخصه است، اینکه داخل شیء چی میگذره رو ملاک قرار نمیده. اگر شما TransparentControlBitmap.DefautBitmap رو تغییر بدید، شیء TransparentControlBitmap که عوض نمیشه، همونه که بود.
مادامی که شیء value در یک مشخصه همون مقدار قبلی باشه Designer تغییری به حساب نمیاره و دلیلی برای ذخیره کردن مجددش نمی بینه.

یه چیز هم اینکه بجز اختصاص دادن متغییری به عنوان فلگ ، چجوری میشه متوجه شد که یه پروپرتی را آیا برنامه نویس مقدار null داد یا اینکه اصلا مقداردهی نشده و بخاطر مقداردهی نشدن هست که null هه؟
دوم اینکه مثلا وقتی داخل کلاس TransparentControlBitmap که هستیم ، میشه وقتی داخلِ یک متد که هستیم ، فهمید که الان این متد داره اجرا میشه ، آیا زمانِ دیزاینر هست (دیزاینر ویژال استودیو باعثِ اجرای این متد شده) یا زمانی که برنامه نویس ، برنامه را اجرا کرده؟
از فلگ می توانید استفاده کنید، اما در NET. روش های دیگه بکار برده شده، از فلگ استفاده نشده. یکی از روش هایی که برخی جاها بکار برده شده اینه که متغیر داخلی مشخصه بجای null یک مقدار خاص و مشخصی داشته باشه، ولی get مشخصه برای اون مقدار خاص مقدار پیشفرض رو برگردونه. فرضا مقدار اولیه StringFormat.GenericDefault باشه، نه null. و مشخصه وقتی متغیر داخلی مقدار StringFormat.GenericDefault داشت null رو برگردونه. یا فرضا مقدار backColor_ مقدار اولیه اش Color.Empty باشه، ولی get در BackColor وقتی مقدار backColor_ برابر Color.Empty بود، مقدار SystemColors.Control رو برگردونه. اینطوری اگه در مشخصه مقدار متغیر backColor_ برابر Color.Empty بود معلومه که هنوز مقدار دهی نشده ولی اگر غیر از Color.Empty بود مقدار دهی شده.
در نظر بگیرید در اینجور موارد اصولا اون متغیر داخلی مشخصه است که باید Serialize بشه، خود مشخصه رو Serialize نمی کنید.
بعد اینکه به نظرتون توی TransparentControlBitmap ، برای پروپرتیِ ControlDisabledBitmap ، قابلیت نال بذارم یا نذارم؟
ControlDisabledBitmap هم که بیت مپی هست وقتی که اون کنترل غیر فعال شد ، رسم میشه.
معنا نداره یه کنترل ، غیر فعال بشه اما رسم اش همون باقی بمونه و تغییری نکنه . درسته؟
بستگی به دید خودتون داره، ممکنه یک کنترل غیر فعال نیازی به ظاهر متفاوت نداشته باشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
باز ناچارم صحبت های قبلی رو تکرار کنم، مشخصه های یک شیء هر چقدر که تغییر کنه، شیء همچنان همون شیء ئه و تغییری نکرده. Designer هم ملاکش برای ذخیره کردن TransparentControlBitmap مقدار مشخصه است، اینکه داخل شیء چی میگذره رو ملاک قرار نمیده. اگر شما TransparentControlBitmap.DefautBitmap رو تغییر بدید، شیء TransparentControlBitmap که عوض نمیشه، همونه که بود.
مادامی که شیء value در یک مشخصه همون مقدار قبلی باشه Designer تغییری به حساب نمیاره و دلیلی برای ذخیره کردن مجددش نمی بینه.

سلامی مجدد
خیلی ممنون استاد .
میدونم ، شی ، همون شی هست . این قضیه را میدونم.
منظورم این بود که درون متد EditValue (در فایل Editor که در پست 1379 دادم) ، اول یه شی جدید از TransparentControlBitmap را درست کردم و پروپرتی هاش مثل پروپرتیِ TransparentControlBitmap.DisabledControlBitmap را مقداردهی کردم و بعد همین شی TransparentControlBitmap را برگردوندم.
حالا این شی ، برگردونده شد . درسته؟
اما بعد از برگردوندن ، در متد TransparentControlBitmap.TransparentControl_ParentChanged ، مقدار پروپرتیِ DisabledControlBitmap اش تغییر کرد و دیزاینر هم مقدار بیت مپِ DisabledControlBitmap ای که تغییر کرد را ذخیره کرد. اما شی TransparentControlBitmap که تغییر نکرد . خوب در اینجا چطور شی TransparentControlBitmap که تغییر نکرد و فقط مقدار عضوش ، یعنی پروپرتیِ DisabledControlBitmap اش تغییر کرد را ذخیره کرد اما من هر چی فقط مقدار اعضاش (مثل همین پروپرتی DefaultBitmap و ...) را تغییر میدادم (اما شی TransparentControlBitmap را تغییر نمیدادم) ، ذخیره نمیکرد؟

از فلگ می توانید استفاده کنید، اما در NET. روش های دیگه بکار برده شده، از فلگ استفاده نشده. یکی از روش هایی که برخی جاها بکار برده شده اینه که متغیر داخلی مشخصه بجای null یک مقدار خاص و مشخصی داشته باشه، ولی get مشخصه برای اون مقدار خاص مقدار پیشفرض رو برگردونه. فرضا مقدار اولیه StringFormat.GenericDefault باشه، نه null. و مشخصه وقتی متغیر داخلی مقدار StringFormat.GenericDefault داشت null رو برگردونه. یا فرضا مقدار backColor_ مقدار اولیه اش Color.Empty باشه، ولی get در BackColor وقتی مقدار backColor_ برابر Color.Empty بود، مقدار SystemColors.Control رو برگردونه. اینطوری اگه در مشخصه مقدار متغیر backColor_ برابر Color.Empty بود معلومه که هنوز مقدار دهی نشده ولی اگر غیر از Color.Empty بود مقدار دهی شده.
در نظر بگیرید در اینجور موارد اصولا اون متغیر داخلی مشخصه است که باید Serialize بشه، خود مشخصه رو Serialize نمی کنید.

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

ممنون . متوجه شدم.
اما منظور من این بود که وقتی از انواعی که ساخته شده استفاده میکنیم ، چی کار کنیم؟
مثلا نوع Bitmap که قبلا ساخته شده اما این قابلیت براش تعبیه نشده .
این مدلی که گفتید ، به درد انواع داده ای ای میخوره که یا از قبل این قابلیت را براش در نظر گرفتن یا ما خودمون یه نوعِ داده ای یا کلاسی درست کنیم که این قابلیت را براش در نظر بگیریم.
مثلا اتریباتسِ خاصی وجود نداره که برای همه ی نوعِ داده ای این قابلیت را بشه استفاده کرد؟

------------------------------

استاد ، شما قبلا گفته بودین هر چقدر یه رویداد را به یه متد متصل کنیم ، فقط یکبار اجرا میشه؟ چون دقیقا یادم نمیاد همچین چیزی گفته باشین ، سئوال میکنم.
صحبت بالا درست نیست . درست میگم؟
چون در کد زیر :

کد:
        private void Button1_Click_1(object sender, EventArgs e)
        {
            this.button1.Click += new EventHandler(this.Button1_Click_1);

            MessageBox.Show("Button1_Click_1");
        }

با هر بار کلیک ، یه بار اضافه تر این رویداداجرا میشه.
 

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد .
میدونم ، شی ، همون شی هست . این قضیه را میدونم.
منظورم این بود که درون متد EditValue (در فایل Editor که در پست 1379 دادم) ، اول یه شی جدید از TransparentControlBitmap را درست کردم و پروپرتی هاش مثل پروپرتیِ TransparentControlBitmap.DisabledControlBitmap را مقداردهی کردم و بعد همین شی TransparentControlBitmap را برگردوندم.
حالا این شی ، برگردونده شد . درسته؟
درسته.

اما بعد از برگردوندن ، در متد TransparentControlBitmap.TransparentControl_ParentChanged ، مقدار پروپرتیِ DisabledControlBitmap اش تغییر کرد و دیزاینر هم مقدار بیت مپِ DisabledControlBitmap ای که تغییر کرد را ذخیره کرد.
ارتباط بین ParentChanged و TransparentControlBitmap چیه؟ شما یک کنترل TransparentControl دارید با نام transparentControl1 که Parent اش panel1 ئه. هر چند بار که شیء TransparentControlBitmap اون کنترل تون رو تغییر بدید، همچنان Parent همون panel1 ئه، ParentChanged در تغییر TransparentControlBitmap چه نقشی داره که فراخوانی بشه؟ Designer وقتی تصمیم به ذخیره سازی میگیره که مقدار مشخصه TransparentControlBitmap تغییر کنه، در هر جایی که کدش نوشته بشه، ربطی به تغییر کردن و نکردن TransparentControlBitmap.DisabledControlBitmap و هر مشخصه دیگری از TransparentControlBitmap نداره. وقتی شما کنترل TransparentControl جدیدی روی فرم قرار میدید یا مشخصه TransparentControlBitmap اش رو به هر روشی تغییر میدید، TransparentControlBitmap ذخیره میشه. ببینید خلاف این مساله رو می توانید در پروژه ای که پیوست کرده بودم ببینید؟

ممنون . متوجه شدم.
اما منظور من این بود که وقتی از انواعی که ساخته شده استفاده میکنیم ، چی کار کنیم؟
مثلا نوع Bitmap که قبلا ساخته شده اما این قابلیت براش تعبیه نشده .
این مدلی که گفتید ، به درد انواع داده ای ای میخوره که یا از قبل این قابلیت را براش در نظر گرفتن یا ما خودمون یه نوعِ داده ای یا کلاسی درست کنیم که این قابلیت را براش در نظر بگیریم.
مثلا اتریباتسِ خاصی وجود نداره که برای همه ی نوعِ داده ای این قابلیت را بشه استفاده کرد؟
نه. تفاوت خاصی وجود نداره که کلاس دست ساز باشه یا نه، چون شما شیء static رو می توانید بیرون از کلاس تعریف کنید، نیازی نیست داخلش باشه.
مهم اینه که برای مقایسه شی static ای که میسازید و سایر اشیاء مقایسه گر مناسب بکار برده بشه، چون هر بار که اسمبلی اجرا میشه اون شیء static مقدار جدیدی داره.
فرضا می دونیم که new Bitmap(1,1) با new Bitmap(1,1) دو تا شیء مجزا هستند و بصورت عادی برابر نیستند، پس Equals پیشفرض Bitmap بدرد مقایسه نمیخوره.
باید در روتین مقایسه شرط کنید که وقتی نتیجه مقایسه true است که ابعادش 1x1 ئه و رنگ اون یک پیکسل اش هم فلان ئه.

استاد ، شما قبلا گفته بودین هر چقدر یه رویداد را به یه متد متصل کنیم ، فقط یکبار اجرا میشه؟ چون دقیقا یادم نمیاد همچین چیزی گفته باشین ، سئوال میکنم.
نه بابا، کی گفتم؟ خدا رو شکر که مطالب قبلی هست : 1258# برای اینکه فقط یکبار اجرا بشه باید فقط یکبار بهش اضافه بشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد.
میگم در کد زیر که پیوست میکنم (که فقط متد InitializeComponent برای ساختِ ظاهر هست) ، چرا TabIndex هایی که دادم ، درست عمل نمیکنن؟
من میخوام وقتی کاربر tab را میزنه ، اول ، از بالا ، سمت چپ کنترل button شروع به فوکوس کردن کنه و هر بار که tab را میزنه ، به کنترل button سمت راست اش بره. بعد ، فوکوس به کنترل های در ردیف پایین تر بیاد و همین منوال طی بشه. (فقط روی کنترل های Label و GroupBox و TransparentControl ، نمیخوام فوکوسی انجام بشه . واسه ی همین TabStop شون را false کردم و TabIndex شون را عدد خیلی بالا (1000) گذاشتم) .
پروپرتی TabIndex بقیه ی کنترل ها را به درستی و به ترتیب از 1 شروع کردم و دادم (پروپرتیِ TabStop شون را true قرار دادم)
ظاهر برنامه (کد زیر) ، هم برابر با عکسی که در پست 1349 گذاشتم ، هست.

بالاخره شما میدونین دلیل این بی نظمیِ در فوکوس شدن ، موقع فشردن کلید Tab (با اونکه همونطور که توضیح دادم ، به ترتیب TabIndex شون را مقداردهی کردم) ، چیه؟
 

پیوست ها

  • TabIndex.rar
    5.6 کیلوبایت · بازدیدها: 3

the_king

مدیرکل انجمن
خیلی ممنون استاد.
میگم در کد زیر که پیوست میکنم (که فقط متد InitializeComponent برای ساختِ ظاهر هست) ، چرا TabIndex هایی که دادم ، درست عمل نمیکنن؟
من میخوام وقتی کاربر tab را میزنه ، اول ، از بالا ، سمت چپ کنترل button شروع به فوکوس کردن کنه و هر بار که tab را میزنه ، به کنترل button سمت راست اش بره. بعد ، فوکوس به کنترل های در ردیف پایین تر بیاد و همین منوال طی بشه. (فقط روی کنترل های Label و GroupBox و TransparentControl ، نمیخوام فوکوسی انجام بشه . واسه ی همین TabStop شون را false کردم و TabIndex شون را عدد خیلی بالا (1000) گذاشتم) .
پروپرتی TabIndex بقیه ی کنترل ها را به درستی و به ترتیب از 1 شروع کردم و دادم (پروپرتیِ TabStop شون را true قرار دادم)
ظاهر برنامه (کد زیر) ، هم برابر با عکسی که در پست 1349 گذاشتم ، هست.

بالاخره شما میدونین دلیل این بی نظمیِ در فوکوس شدن ، موقع فشردن کلید Tab (با اونکه همونطور که توضیح دادم ، به ترتیب TabIndex شون را مقداردهی کردم) ، چیه؟
هیچوقت نه TabStop رو برای Label و GroupBox ها false کنید و نه TabInde شون رو خارج از ترتیب تنظیم کنید. با همون ترتیب چپ به راست، بالا به پایین بهشون شماره میدید. کنترل Label و GroupBox خودشون که هیچوقت نمیتونند Focus بگیرند، ولی اگر Text اش رو Default Bitmap& قرار بدید، بخاطر اون &، در هنگام اجرا با زدن کلید Alt بصورت Default Bitmap دیده میشه و با ترکیب کلیدی Alt + D اولین کنترل بعد از اون که قابل Focus گرفتن هست فعال میشه.
چه & رو تعریف کرده باشید و چه نکرده باشید، در ترتیب TabIndex ها Label و GroupBox و هر کنترل دیگری که مشخصه TabIndex رو پنهان نکرده خارج از ترتیب تنظیم نمی کنید.
صرفا برای کنترل هایی TabStop رو غیر فعال خواهید کرد که به دلیلی قرار نیست توسط کاربر انتخاب بشن و کاری داخلشون انجام بده، مثلا برای ListBox ای که صرفا داره گزارشی رو نمایش میده و قرار نیست کاربر گزینه ای رو داخلش انتخاب کنه.
برای مشخص کردن TabIndex ها هم که مقدارشون رو دستی وارد نمی کنید، در منوی View از گزینه Tab Order استفاده می کنید و به ترتیب روی کنترل ها کلیک می کنید، اول GroupBox، بعد کنترل های داخل GroupBox، سپس GroupBox بعدی و سپس کنترل های داخلش و ... و هر زمان تمامی کنترل ها رو کلیک کرده باشید و یا هر جا کلید ESC رو فشار بدید روال تنظیم TabIndex ها تموم میشه. اگر GroupBox ای شماره 2 باشه، باید اولین کنترل داخلش 2.0 باشه، اگر چیزی مثل 2.4 بود، به 2.0 تغییرش می دهید. روی هر کنترل هر چند بار که لازم شد کلیک می کنید تا به مقدار مناسب برگرده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد. :rose:
میگم توی دیزاینر ، وقتی transparent control ام که قبلا روی فرم بوده را حذف میکنم ، حالا که یه شیِ دیگه ی transparent control رو میخوام اضافه کنم ، دیزاینر ارور زیر رو میده و رسم کنترل ناقص میشه (البته همیشه ممکنه این اتفاق نیفته . البته اگه شیِ قبلی transparent control را حذف کنم و شی جدید transparent control را بخوام اضافه کنم ، این اتفاق میافته ها اونم ممکنه گاها بیفته. نه مثلا بخوام فقط شی transparent control را اضافه کنم) :

1.JPG

دیگه از اون به بعد ، هر کنترل transparent control ای که بعدش بخوام توی دیزاینر اضافه کنم ، همین ارور رو میده مگر اینکه ویژال استودیو را ببندم و دوباره واردش بشم که این مشکل حل میشه و کنترل های transparent control را میتونم در دیزاینر به فرم اضافه کنم.
این ارور نشون میده مشکل از کدهای کنترل transparent control هه.
اما من بصورت کدنویسی که تست کردم (کنترل transparent control قبلی را dispose کردم و دو کنترل جدید transparent control را توسط متد سازنده ی پیش فرض ساختم و به فرم اضافه کردم) ، این مشکل بازتولید نشد و این مشکل را نداشت :

کد:
            this.transparentControl1.Dispose();

            TransparentControl TC_2 = new TransparentControl();
            TransparentControl TC_3 = new TransparentControl();

            this.Controls.Add(TC_2);
            this.Controls.Add(TC_3);

الان اگه مشکل از کدهای transparent control باشه ، پس چرا در موقع کدنویسی این مشکل باز تولید نمیشه و فقط در دیزاینر ، این ارور اتفاق میافته؟
بعد اینکه آیا در زمان dispose شدن یک کنترل ، باید کد خاصی را نوشت؟ اگه آره ، چه کدی؟
خیلی ممنون
 

the_king

مدیرکل انجمن
خیلی ممنون استاد. :rose:
میگم توی دیزاینر ، وقتی transparent control ام که قبلا روی فرم بوده را حذف میکنم ، حالا که یه شیِ دیگه ی transparent control رو میخوام اضافه کنم ، دیزاینر ارور زیر رو میده و رسم کنترل ناقص میشه (البته همیشه ممکنه این اتفاق نیفته . البته اگه شیِ قبلی transparent control را حذف کنم و شی جدید transparent control را بخوام اضافه کنم ، این اتفاق میافته ها اونم ممکنه گاها بیفته. نه مثلا بخوام فقط شی transparent control را اضافه کنم) :

مشاهده پیوست 112777

دیگه از اون به بعد ، هر کنترل transparent control ای که بعدش بخوام توی دیزاینر اضافه کنم ، همین ارور رو میده مگر اینکه ویژال استودیو را ببندم و دوباره واردش بشم که این مشکل حل میشه و کنترل های transparent control را میتونم در دیزاینر به فرم اضافه کنم.
این ارور نشون میده مشکل از کدهای کنترل transparent control هه.
اما من بصورت کدنویسی که تست کردم (کنترل transparent control قبلی را dispose کردم و دو کنترل جدید transparent control را توسط متد سازنده ی پیش فرض ساختم و به فرم اضافه کردم) ، این مشکل بازتولید نشد و این مشکل را نداشت :

کد:
            this.transparentControl1.Dispose();

            TransparentControl TC_2 = new TransparentControl();
            TransparentControl TC_3 = new TransparentControl();

            this.Controls.Add(TC_2);
            this.Controls.Add(TC_3);

الان اگه مشکل از کدهای transparent control باشه ، پس چرا در موقع کدنویسی این مشکل باز تولید نمیشه و فقط در دیزاینر ، این ارور اتفاق میافته؟
بعد اینکه آیا در زمان dispose شدن یک کنترل ، باید کد خاصی را نوشت؟ اگه آره ، چه کدی؟
خیلی ممنون
شرایط رو با کدنویسی میشه ایجاد کرد، ولی مساله اینجا است که شما بخوبی بدونید شرایطی که منجر به خطا میشه چیه.
شما هم باید اون رخدادی که روتین اش منجر به خطا میشه رو بشناسید و هم کاری کنید که حتما اتفاق بیافته و هم Dispose شدن یا نابود شدن شیء رو دقیقا همون زمانی انجام بدید که تو اون شرایط خطا رخ داده. یکم قبل و یکم بعد ممکن خیلی در نتیجه موثر باشه. اغلب اوقات شما در کدتون دارید یک Dispose رو انجام میدید ولی زمانبندی اش با اون شرایط مطابقت نداره.
فرضا اگر من بدونم که وسط رخداد Paint ام خطا اتفاق می افته، باید بدونم که اگر Dispose اش کردم و Paint ای بعد از اون رخ نداد این شرایطی که میخواستم رو ایجاد نکردم.

وقتی کنترلی Dispose میشه هر عملیاتی که مربوط به پنجره اش بوده دیگه عمل نمی کنه و نباید بکار برده بشه چون پنجره ای در کار نیست و نابود شده.
غیر از اون هر شیء ای هم خودتون ساختید و Dispose شدنی است باید Dispose کنید و کنار بذارید، مثلا Brush و Font و ... و رخدادی که به شیء دیگری متصل کردید رو هم در نظر بگیرید که داخلش نابود شدن شی یا Dispose شدنش شرط عدم انجام باشه.
اشکال کار که معمولا منجر به خطا است، مربوط به زمانی است که شما بین چند شیء مستقل ارتباط برقرار کردید. فرضا بین رخدادی در Parent و کنترل تون، یا فرضا بین TransparentControlBitmap و کنترل تون که حواس روتین به نابود شدن شیء یا Dispose شدنش نیست. فرضا شما کنترل تون رو Dispose کردید که دیگه پنجره نداره و حتی فراتر از اون شیء اش نابود شده و از روی فرم برداشته شده، ولی شیء دیگری مثلا Parent اش یا TransparentControlBitmap ای تو باغ نیست و داره همچنان سعی می کنه بهش دسترسی پیدا کنه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
شرایط رو با کدنویسی میشه ایجاد کرد، ولی مساله اینجا است که شما بخوبی بدونید شرایطی که منجر به خطا میشه چیه.
شما هم باید اون رخدادی که روتین اش منجر به خطا میشه رو بشناسید و هم کاری کنید که حتما اتفاق بیافته و هم Dispose شدن یا نابود شدن شیء رو دقیقا همون زمانی انجام بدید که تو اون شرایط خطا رخ داده. یکم قبل و یکم بعد ممکن خیلی در نتیجه موثر باشه. اغلب اوقات شما در کدتون دارید یک Dispose رو انجام میدید ولی زمانبندی اش با اون شرایط مطابقت نداره.
فرضا اگر من بدونم که وسط رخداد Paint ام خطا اتفاق می افته، باید بدونم که اگر Dispose اش کردم و Paint ای بعد از اون رخ نداد این شرایطی که میخواستم رو ایجاد نکردم.

وقتی کنترلی Dispose میشه هر عملیاتی که مربوط به پنجره اش بوده دیگه عمل نمی کنه و نباید بکار برده بشه چون پنجره ای در کار نیست و نابود شده.
غیر از اون هر شیء ای هم خودتون ساختید و Dispose شدنی است باید Dispose کنید و کنار بذارید، مثلا Brush و Font و ... و رخدادی که به شیء دیگری متصل کردید رو هم در نظر بگیرید که داخلش نابود شدن شی یا Dispose شدنش شرط عدم انجام باشه.
اشکال کار که معمولا منجر به خطا است، مربوط به زمانی است که شما بین چند شیء مستقل ارتباط برقرار کردید. فرضا بین رخدادی در Parent و کنترل تون، یا فرضا بین TransparentControlBitmap و کنترل تون که حواس روتین به نابود شدن شیء یا Dispose شدنش نیست. فرضا شما کنترل تون رو Dispose کردید که دیگه پنجره نداره و حتی فراتر از اون شیء اش نابود شده و از روی فرم برداشته شده، ولی شیء دیگری مثلا Parent اش یا TransparentControlBitmap ای تو باغ نیست و داره همچنان سعی می کنه بهش دسترسی پیدا کنه.

خیلی ممنون استاد .
تاسوعا و عاشورای حسینی را بهتون تسلیت میگم و ان شاءا... عزا داری تون قبول باشه.


منظورتون اینه که بعد از اینکه کنترل TransparentControl ، نابود و dispose شد ، رویدادهای شیِ TransparentControl که به کلاس های TransparentControlBitmap و TransparentControlText متصل کردم را عدم اتصال انجام بدم؟
و همچنین پروپرتی هایی که به هم متصل هستن (درون کلاس های TransparentControlBitmap و TransparentControlText ،به کلاس TransparentControl مربوط هستند) و بقیه ی پروپرتی های مربوطه در این دو کلاس را هم null کنم؟
پروپرتی هایی که dispose شدنی در این دو کلاس (درون کلاس های TransparentControlBitmap و TransparentControlText) هستند را هم dispose کنم؟
اما اینکه به اعضای پروپرتی هایی که در کلاس TransparentControl تعریف کردم را ، این عملیات ( عملیاتِ null کردن و dispose کردن و قطع کردنِ اتصال رویدادهایی از این کلاس که به دو کلاسِ TransparentControlBitmap و TransparentControlText قبلا متصل شده بودند) را انجام بدم یا اینکه با dispose کردنشدنِ این کنترل ، خودش اتوماتیک این کارها را انجام میده و لازم به انجام کار خاصی توسط من در کلاس TransparentControl نیست؟

-------------------------------

مشکلم را متوجه شدم.
وقتی یه کنترلی که قبلا در یک لوکیشن ای اضافه کرده بودم (مثلا در نقطه ی 100 و 100) و بعد حذف و dispose اش کردم و بعد یه کنترل TransparentControl دیگه ای را میخوام در یک نقطه ای که با باند کنترلِ قبلی که حذف شد ، باند مشترک داشته باشه ، اضافه کنم ، در متد IsAtForeOrBackgroundControl و در خط IntPtr handleNextControl = this.Handle; ، بخاطر اینکه شیِ قبلیِ TransparentControl ، یعنی this در این خط ، قبلا dispose شد ، سعی داره بهش دسترسی داشته باشه اما نمیتونه :

کد:
        private void DisposeTC_Click(object sender, EventArgs e)
        {
            this.transparentControl2.Dispose();
        }

        private void CreateTC_Click(object sender, EventArgs e)
        {
            this.TC_3 = new TransparentControl();
            this.TC_3.Location = new Point(500, 100);
            this.TC_3.Name = "TC_3";
            this.Controls.Add(TC_3);
        }

کنترل transparentControl2 ، کنترلی بود که روی دیزاینر وجود داشت و اول حذف شد و بعد کنترل TC_3 ، روی همون باند (که کلا دو شی TC_3 و transparentControl2 ، نقطه ی مشترک داشته باشن) ، اضافه شد. و اون ارور را میده.
ماجرا از این قراره که وقتی پروپرتیِ AutoCalculateForeBackgroundControls از شیِ TransparentControl ، مقدار true باشه (که همیشه در متد پیش فرض ، true میشه) ، این کنترل ، همه ی کنترل های برادر و خواهرش (که در یک والد هستند . البته بجز خودش) را جستجو میکنه تا مشخص کنه کنترل هایی که پشت زمینه اش هستند ، کدوم ها هستند و کنترل هایی که جلوی زمینه اش هستند ، کدوم ها هستند.
بنابراین ، چون کنترلِ TC_3 ، به همون باندی اضافه شد که نقطه ی مشترک با transparentControl2 داره ، سعی میکنه به کنترل transparentControl2 دسترسی داشته باشه (برای همون قضیه ای که در بالا گفتم) اما این کنترل transparentControl2 ، قبلا dispose شده بود.


اما نکته ی مهمی که تعجب میکنم ازش اینه که شی ای که dispose شد (کنترل transparentControl2) ، مگه اشاره گرش را از دست نمیده؟ یعنی دیگه والدش ، اشاره گری بهش نداره دیگه؟ درسته؟
پس چطور ممکنه که کنترل TC_3 که کنترل های درون والدش را چک میکنه ، به شی و کنترلی از والدش دسترسی پیدا کنه که اصلا اشاره گری نداره؟!!
به نظرتون ، با چه روشی (شیوه ی کلی منظورمه . منظورم راهنمایی کدنویسی نیست) ، این مشکل را حل کنم؟
خیلی ممنون استاد.
 
آخرین ویرایش:

the_king

مدیرکل انجمن
خیلی ممنون استاد .
تاسوعا و عاشورای حسینی را بهتون تسلیت میگم و ان شاءا... عزا داری تون قبول باشه.


منظورتون اینه که بعد از اینکه کنترل TransparentControl ، نابود و dispose شد ، رویدادهای شیِ TransparentControl که به کلاس های TransparentControlBitmap و TransparentControlText متصل کردم را عدم اتصال انجام بدم؟
گاهی کافی نیست، زمانی عدم اتصال کفایت می کنه که در فاصله بین Dispose شدن و عدم اتصال اون رخداد در هیچ حالتی پیش نیاد. ممکنه شما زمانی اتصال رو از بین می برید که همون لحظه در حال اجرا شدن روتین همون رخداد ئه.

و همچنین پروپرتی هایی که به هم متصل هستن (درون کلاس های TransparentControlBitmap و TransparentControlText ،به کلاس TransparentControl مربوط هستند) و بقیه ی پروپرتی های مربوطه در این دو کلاس را هم null کنم؟
پروپرتی هایی که dispose شدنی در این دو کلاس (درون کلاس های TransparentControlBitmap و TransparentControlText) هستند را هم dispose کنم؟
null کردن دلیل منطقی میخواد، ارتباطی با Dispose شدن نداره. وقتی استفاده کننده شون از بین بره خودشون هم توسط GC آزاد میشن، پس لزومی نداره که اول مشخصه ها null بشن.
مشخصه ها رو صرفا زمانی null می کنید که قراره استفاده ازشون ادامه پیدا کنه ولی بدون وجود فلان شیء.
اگر قراره کنترلی نابود بشه دلیلی نداره که اول مشخصه هاش null بشه، چون در نتیجه تاثیری نداره.
ولی هر شیء ای که ساختید و Dispose شدنی است باید همون موقع که دیگه استفاده ای نداره Dispose بشه، این یک قاعده کلی است که همیشه باید رعایت کنید.

اما اینکه به اعضای پروپرتی هایی که در کلاس TransparentControl تعریف کردم را ، این عملیات ( عملیاتِ null کردن و dispose کردن و قطع کردنِ اتصال رویدادهایی از این کلاس که به دو کلاسِ TransparentControlBitmap و TransparentControlText قبلا متصل شده بودند) را انجام بدم یا اینکه با dispose کردنشدنِ این کنترل ، خودش اتوماتیک این کارها را انجام میده و لازم به انجام کار خاصی توسط من در کلاس TransparentControl نیست؟
قبلا بارها در موردش صحبت کردیم. ارتباطی بین Dispose و null شدن که نیست. شی ای که در NET. تعریف شده که با Dispose نابود نمیشه، همانطور که null شدن هم باعث Dispose شدن نمیشه.
اون Dispose فقط و فقط یک روتین ئه که هر کاری داخلش تعریف شده انجام میده و روی بقای شیء هیچ تاثیری نداره، هیچ کار پیشفرضی انجام نمیده و هیچ چیزی جز آنچه برنامه نویس میخواد انجام نمیده.
ممکنه شیء ای رو از همون ابتدای برنامه Dispose کنید و بعد در ادامه از مشخصه ها و رخداد هایش استفاده کنید، Dispose نه کاری به دسترسی به شیء داره و نه رخداد های متصل شده اش.
GC ئه که شیء رو نابود می کنه و هر زمانی که لازم بدونه، به Dispose ربطی نداره. Dispose صرفا منابعی که معمولا Unmanaged بوده رو آزاد میکنه که از مسئولیت GC خارج ئه به علاوه هر عملیات دیگری که در روتینش تعریف شده. ممکنه به دلیل Dispose شدن و از دست دادن منابع برخی رخداد ها دیگر اتفاق نیافتند، ولی این به معنای عدم اتصال نیست و Dispose هم کاری به این اتصال ها نداره.

اما نکته ی مهمی که تعجب میکنم ازش اینه که شی ای که dispose شد (کنترل transparentControl2) ، مگه اشاره گرش را از دست نمیده؟ یعنی دیگه والدش ، اشاره گری بهش نداره دیگه؟ درسته؟
پس چطور ممکنه که کنترل TC_3 که کنترل های درون والدش را چک میکنه ، به شی و کنترلی از والدش دسترسی پیدا کنه که اصلا اشاره گری نداره؟!!
به نظرتون ، با چه روشی (شیوه ی کلی منظورمه . منظورم راهنمایی کدنویسی نیست) ، این مشکل را حل کنم؟
خیلی ممنون استاد.
نه. Dispose فقط یک روتین ئه، اگر متغیر a به یک شیء ای اشاره میکنه، تنها دلیلی که باعث میشه a مقدارش null بشه اینه که خودتون مقدار null رو داخلش قرار بدید.
یک متد مثل Dispose که نمیتونه متغیری که به این شیء اشاره میکنه رو null کنه.
کد:
    class MyClass : IDisposable
    {
        public void Dispose()
        {
        }
    }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
گاهی کافی نیست، زمانی عدم اتصال کفایت می کنه که در فاصله بین Dispose شدن و عدم اتصال اون رخداد در هیچ حالتی پیش نیاد. ممکنه شما زمانی اتصال رو از بین می برید که همون لحظه در حال اجرا شدن روتین همون رخداد ئه.


null کردن دلیل منطقی میخواد، ارتباطی با Dispose شدن نداره. وقتی استفاده کننده شون از بین بره خودشون هم توسط GC آزاد میشن، پس لزومی نداره که اول مشخصه ها null بشن.
مشخصه ها رو صرفا زمانی null می کنید که قراره استفاده ازشون ادامه پیدا کنه ولی بدون وجود فلان شیء.
اگر قراره کنترلی نابود بشه دلیلی نداره که اول مشخصه هاش null بشه، چون در نتیجه تاثیری نداره.
ولی هر شیء ای که ساختید و Dispose شدنی است باید همون موقع که دیگه استفاده ای نداره Dispose بشه، این یک قاعده کلی است که همیشه باید رعایت کنید.


قبلا بارها در موردش صحبت کردیم. ارتباطی بین Dispose و null شدن که نیست. شی ای که در NET. تعریف شده که با Dispose نابود نمیشه، همانطور که null شدن هم باعث Dispose شدن نمیشه.
اون Dispose فقط و فقط یک روتین ئه که هر کاری داخلش تعریف شده انجام میده و روی بقای شیء هیچ تاثیری نداره، هیچ کار پیشفرضی انجام نمیده و هیچ چیزی جز آنچه برنامه نویس میخواد انجام نمیده.
ممکنه شیء ای رو از همون ابتدای برنامه Dispose کنید و بعد در ادامه از مشخصه ها و رخداد هایش استفاده کنید، Dispose نه کاری به دسترسی به شیء داره و نه رخداد های متصل شده اش.
GC ئه که شیء رو نابود می کنه و هر زمانی که لازم بدونه، به Dispose ربطی نداره. Dispose صرفا منابعی که معمولا Unmanaged بوده رو آزاد میکنه که از مسئولیت GC خارج ئه به علاوه هر عملیات دیگری که در روتینش تعریف شده. ممکنه به دلیل Dispose شدن و از دست دادن منابع برخی رخداد ها دیگر اتفاق نیافتند، ولی این به معنای عدم اتصال نیست و Dispose هم کاری به این اتصال ها نداره.


نه. Dispose فقط یک روتین ئه، اگر متغیر a به یک شیء ای اشاره میکنه، تنها دلیلی که باعث میشه a مقدارش null بشه اینه که خودتون مقدار null رو داخلش قرار بدید.
یک متد مثل Dispose که نمیتونه متغیری که به این شیء اشاره میکنه رو null کنه.
کد:
    class MyClass : IDisposable
    {
        public void Dispose()
        {
        }
    }

خیلی ممنون استاد.
اگه متد Dispose را override کنیم ، موقعِ dispose شدن ، اولین متدی هه که اجرا میشه.
حالا توی این متد ، میشه کاری کرد و کدی نوشت که متدهایی که با On شروع میشن ، اجرا نشن؟
مثل متد OnParentChanged و هر متدی که اولش On داره و ما در کلاس فرزند ، یعنی کلاس TransparentControl ، اون متد را override کردیم.
 

the_king

مدیرکل انجمن
خیلی ممنون استاد.
اگه متد Dispose را override کنیم ، موقعِ dispose شدن ، اولین متدی هه که اجرا میشه.
حالا توی این متد ، میشه کاری کرد و کدی نوشت که متدهایی که با On شروع میشن ، اجرا نشن؟
چرا نباید اجرا بشن؟ یک شیء OnParentChanged رو زمانی اجرا می کنه که Parent اش تغییر کرده. اگر نمیخواهید از تغییر Parent با خبر بشید بهش متد متصل نکنید.
اینکه یک کنترل Dispose بشه نه اتفاق بدی است و نه اینکه بعد Dispose بعضی رخداد هایش رخ بده اشتباه ئه. شما باید کد خودتون رو اصلاح کنید، نه اینکه رخداد ها رو از کار بندازید.
قبلا هم گفتم، شما در کد هایی که می نویسید باید اولا بررسی کنید که این شیء فلان که میخواهید بهش دسترسی پیدا کنید null نباشه و ثانیا اگه موردی مثل کنترل ئه و میخواهید با عملیاتی مربوط به پنجره ها کار کنید، IsDisposed اش true نباشه. نه اینکه رخداد های کنترل رو کور کنید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
اگر قراره کنترلی نابود بشه دلیلی نداره که اول مشخصه هاش null بشه، چون در نتیجه تاثیری نداره.

خیلی ممنون استاد .
الان GC (هر وقت دلش بخواد) ، زمانی اون شی را از بین میبره که اشاره گری به اون شی نباشه؟ اینکه dispose بشه یا نه ، ربطی به این نداره که GC (هر وقت دلش بخواد) آزادش کنه . درسته؟
بنابراین زمانی که شی ای null بشه و اشاره گر دیگری هم نداشته باشه ، دیگه فرقی نداره اعضا و پروپرتی های اون شی را هم دونه دونه null کنیم. درسته؟ یعنی null کردن اعضاش ، تاثیری نداره که GC (هر وقت دلش بخواد) اون شی را از حافظه ی رم آزاد کنه یا نه.

دوم اینکه تا زمانی که کنترل مون باقی هست و dispose نشد ، اگه برای یک عضو و پروپرتی از این کنترل (مثلا پروپرتیِ TransparentControlText در کنترل TransparentControl) ، شی ای داشته باشه اما باز دوباره ، یک شیِ جدیدی به اون پروپرتی بدیم ، در این صورت لازمه که قبل از اختصاص دادنِ شیِ جدید ، اون شیِ قبلی را dispose کنیم؟

ولی هر شیء ای که ساختید و Dispose شدنی است باید همون موقع که دیگه استفاده ای نداره Dispose بشه، این یک قاعده کلی است که همیشه باید رعایت کنید.

داخلِ کلاس TransparentControlText ، اعضا و پروپرتی های مختلف هست که قابل dispose شدن هه . مثلا یکی اش TextFont هه. خوب من اگه موقعی که کنترلِ TransparentControl ای که به این شیِ TransparentControlText مربوط میشه ، بخواد dispose بشه و من همون زمان پروپرتیِ TextFont را dispose کنم ، ممکنه کاربر ، فونتِ یک کنترلِ دیگه (مثلا فونت کنترل والد) را به این پروپرتی داده باشه . در اون صورت ، دیگه فونت اون کنترل هم dispose میشه .
یا اگه کاربر هم خودش فونت را مقداردهی نکنه ، خودش ، مقدار فونتِ والد را بهش میده.
پس موقعِ dispose شدن ، اشیاء dispose شدنی را dispose نکنم؟
اگه dispose کنم ، راهکار تون را برای حل این مشکل میگین؟
ممنون
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
الان GC (هر وقت دلش بخواد) ، زمانی اون شی را از بین میبره که اشاره گری به اون شی نباشه؟ اینکه dispose بشه یا نه ، ربطی به این نداره که GC (هر وقت دلش بخواد) آزادش کنه . درسته؟
مادامی که شیء جایی مورد استفاده است و بهش ارجاعی وجود داره که GC آزادش نمی کنه. GC صرفا موارد بلا استفاده رو آزاد میکنه. شیء ای که Dispose نشده رو هم آزاد می کنه و برایش فرقی نمی کنه که شیء Dispose شده یا نه، اما این یک ایراد در کار برنامه نویس ئه که Dispose اش نکرده رهایش کرده باشه، چون GC در مورد Dispose شدن نقشی نداره و فقط منابع مدیریت شده مربوط به خودش رو آزاد میکنه و بخش منابع مدیریت نشده شیء آزاد نشده میمونه که منتهی میشه به مواردی مثل Memory Leak و غیره. GC مسئولیتی در مورد منابع مدیریت نشده نداره و Dispose کردن وظیفه برنامه نویسه. برای همینه که در مورد منابع Dispose شدنی { } using توصیه میشه.

بنابراین زمانی که شی ای null بشه و اشاره گر دیگری هم نداشته باشه ، دیگه فرقی نداره اعضا و پروپرتی های اون شی را هم دونه دونه null کنیم. درسته؟ یعنی null کردن اعضاش ، تاثیری نداره که GC (هر وقت دلش بخواد) اون شی را از حافظه ی رم آزاد کنه یا نه.
نه اهمیتی نداره. شما شیء رو که null نمی کنید، متغیری که بهش اشاره میکرد رو null می کنید. اون شیء بلااستفاده شده و در ادامه آماده اینه که توسط GC نابود بشه و در آینده چنین خواهد شد و اگر در مشخصه هایش به اشیاء دیگری هم ارجاعی وجود داشته با از بین رفتن شیء، اون اشیاء هم ارجاع شون رو از دست میدن و در نتیجه خودشون هم در نوبت نابود شدن قرار میگیرند، مگر اینکه در جای دیگری هم بهشون ارجاعی باقی مونده باشه. پس دلیلی وجود نداره که بخواهید زودتر مشخصه ها رو null کنید.

دوم اینکه تا زمانی که کنترل مون باقی هست و dispose نشد ، اگه برای یک عضو و پروپرتی از این کنترل (مثلا پروپرتیِ TransparentControlText در کنترل TransparentControl) ، شی ای داشته باشه اما باز دوباره ، یک شیِ جدیدی به اون پروپرتی بدیم ، در این صورت لازمه که قبل از اختصاص دادنِ شیِ جدید ، اون شیِ قبلی را dispose کنیم؟
بله، حتما. شما از لحظه ای که با new ایجاد اش کردید در قبال اون شیء Dispose شدنی مسئولیت دارید، وظیفه Dispose شدنش با شما است و باید در اولین فرصت که دیگه بهش نیازی نیست Dispose اش کنید.

داخلِ کلاس TransparentControlText ، اعضا و پروپرتی های مختلف هست که قابل dispose شدن هه . مثلا یکی اش TextFont هه. خوب من اگه موقعی که کنترلِ TransparentControl ای که به این شیِ TransparentControlText مربوط میشه ، بخواد dispose بشه و من همون زمان پروپرتیِ TextFont را dispose کنم ، ممکنه کاربر ، فونتِ یک کنترلِ دیگه (مثلا فونت کنترل والد) را به این پروپرتی داده باشه . در اون صورت ، دیگه فونت اون کنترل هم dispose میشه .
یا اگه کاربر هم خودش فونت را مقداردهی نکنه ، خودش ، مقدار فونتِ والد را بهش میده.
پس موقعِ dispose شدن ، اشیاء dispose شدنی را dispose نکنم؟
اگه dispose کنم ، راهکار تون را برای حل این مشکل میگین؟
ممنون
شما فقط شیء ای رو در کلاسی Dispose می کنید که خود کلاس ایجاد کننده اش باشه، نه فرضا تمام اشیاء Font ای که بهشون دسترسی دارید.
از طرف دیگه Dispose شدن هر شیء باید منابعی رو آزاد کنه که خود شیء ایجاد کرده، نه سایر اشیاء مرتبط. مثلا یک کنترل وقتی Dispose میشه قرار نیست Font خودش رو هم Dispose کنه چون اصولا خودش ایجاد کننده Font اش که نبوده، Designer بهش یک Font ای رو داده و اونم ازش استفاده کرده.
مثلا اگر TransparentControlText در کدی ایجاد کننده شیء Font ای بوده، Dispose داخل TransparentControlText باید اون Font رو آزاد کنه، نه Dispose داخل TransparentControl. اون Font ربطی به Dispose شدن TransparentControl نداره. یا اگر TransparentControl ایجاد کننده یک TransparentControlText بوده که Dispose شدنی هم هست، Dispose کردن TransparentControlText وظیفه TransparentControl ئه.

یک روشی که میتوانید روی Dispose کردن اشیاء بکار ببرید اینه که برای اشیاء ای که خودتون داخل کلاس میسازید یک لیست داشته باشید،
مثلا ;()<internal List<object> _disposeMe = new List<object که هر وقت شیء ای مثلا یک font رو خود کلاس ساخت، داخل مجموعه اضافه اش کنید، ;disposeMe.Add(font)_ و در متد Dispose کلاس محتویات مجموعه رو یکی یکی داخل حلقه Dispose کنید :
کد:
            foreach (IDisposable obj in _disposeMe)
            {
                obj.Dispose();
            }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
مادامی که شیء جایی مورد استفاده است و بهش ارجاعی وجود داره که GC آزادش نمی کنه. GC صرفا موارد بلا استفاده رو آزاد میکنه. شیء ای که Dispose نشده رو هم آزاد می کنه و برایش فرقی نمی کنه که شیء Dispose شده یا نه، اما این یک ایراد در کار برنامه نویس ئه که Dispose اش نکرده رهایش کرده باشه، چون GC در مورد Dispose شدن نقشی نداره و فقط منابع مدیریت شده مربوط به خودش رو آزاد میکنه و بخش منابع مدیریت نشده شیء آزاد نشده میمونه که منتهی میشه به مواردی مثل Memory Leak و غیره. GC مسئولیتی در مورد منابع مدیریت نشده نداره و Dispose کردن وظیفه برنامه نویسه. برای همینه که در مورد منابع Dispose شدنی { } using توصیه میشه.


نه اهمیتی نداره. شما شیء رو که null نمی کنید، متغیری که بهش اشاره میکرد رو null می کنید. اون شیء بلااستفاده شده و در ادامه آماده اینه که توسط GC نابود بشه و در آینده چنین خواهد شد و اگر در مشخصه هایش به اشیاء دیگری هم ارجاعی وجود داشته با از بین رفتن شیء، اون اشیاء هم ارجاع شون رو از دست میدن و در نتیجه خودشون هم در نوبت نابود شدن قرار میگیرند، مگر اینکه در جای دیگری هم بهشون ارجاعی باقی مونده باشه. پس دلیلی وجود نداره که بخواهید زودتر مشخصه ها رو null کنید.


بله، حتما. شما از لحظه ای که با new ایجاد اش کردید در قبال اون شیء Dispose شدنی مسئولیت دارید، وظیفه Dispose شدنش با شما است و باید در اولین فرصت که دیگه بهش نیازی نیست Dispose اش کنید.


شما فقط شیء ای رو در کلاسی Dispose می کنید که خود کلاس ایجاد کننده اش باشه، نه فرضا تمام اشیاء Font ای که بهشون دسترسی دارید.
از طرف دیگه Dispose شدن هر شیء باید منابعی رو آزاد کنه که خود شیء ایجاد کرده، نه سایر اشیاء مرتبط. مثلا یک کنترل وقتی Dispose میشه قرار نیست Font خودش رو هم Dispose کنه چون اصولا خودش ایجاد کننده Font اش که نبوده، Designer بهش یک Font ای رو داده و اونم ازش استفاده کرده.
مثلا اگر TransparentControlText در کدی ایجاد کننده شیء Font ای بوده، Dispose داخل TransparentControlText باید اون Font رو آزاد کنه، نه Dispose داخل TransparentControl. اون Font ربطی به Dispose شدن TransparentControl نداره. یا اگر TransparentControl ایجاد کننده یک TransparentControlText بوده که Dispose شدنی هم هست، Dispose کردن TransparentControlText وظیفه TransparentControl ئه.

یک روشی که میتوانید روی Dispose کردن اشیاء بکار ببرید اینه که برای اشیاء ای که خودتون داخل کلاس میسازید یک لیست داشته باشید،
مثلا ;()<internal List<object> _disposeMe = new List<object که هر وقت شیء ای مثلا یک font رو خود کلاس ساخت، داخل مجموعه اضافه اش کنید، ;disposeMe.Add(font)_ و در متد Dispose کلاس محتویات مجموعه رو یکی یکی داخل حلقه Dispose کنید :
کد:
            foreach (IDisposable obj in _disposeMe)
            {
                obj.Dispose();
            }

آها.
خیلی ممنون استاد.
پس اگه اشتباه نکنم ، منظورتون اینه که فقط اشیاء هایی که (dispose شدنی هست و) فقط اولا خودم ساختم (نه اینکه شیِ dispose شدنی ای که از برنامه نویس دریافت کردم) و دوما شی جدیدی برایش در نظر گرفتم (new کردم) (نه هر شی ای که از کنترل یا جاهای دیگه مثل همون قضیه ی فونت والد ای که گفتم ، گرفته باشم) را در لیست dispose بذارم و هر وقت کنترل ام dispose شد ، یا شیِ قبلیِ مربوطه ، null شد ، اون شیِ مورد نظر را dispose کنم.
منظورتون همین هه . درست میگم؟



اما باز یک مسئله پیش میاد.
اینکه اشیاءهای dispose شدنی که ممکنه مشترکا استفاده شده باشن (مثل همون فونت کنترل والد) یا اصلا مشترکا استفاده نشده باشن و ما نمیدونیم (مثلا شیِ dispose شدنی ای که برنامه نویس داده باشه اما اگه اشتباه نکنم ، شما در بالا گفتین که هر چی کاربر شی dispose شدنی رو میده ، dispose نکنم) را چی کار کنم؟
از طرفی هم خودتون گفتین که هر شی dispose شدنی ، بهتره برای آزاد کردن حافظه ی unmanaged اش (و حتی حافظه ی managed اش) ، dispose و آزاد بشه.
خوب ، تکلیف این نوع اشیاءهایی که dispose شدنی اند (و خیلی هم ممکنه باشند . چه اونهایی که توی شی قبلی استفاده شدند و با تعویض شی ، dispose نشدند و ...) و سر آخر ، کاربر نهایی بخواد نرم افزار و برنامه ای که این کنترل مون در اون استفاده شد را ببنده و این همه اشیاء dispose شدنی ای که dispose نشدند ، چی میشه؟
پس بهتر نیست ، علاوه بر راهکاری که در بالا دادین (پاراگراف اول که گفتم) ، یه لیست static ای از این نوع اشیاء های dispose شدنی (که برنامه نویس میده یا ما از کنترل های دیگه استفاده میکنیم) در نظر بگیریم تا برنامه نویس وقتی میخواد برنامه اش بسته بشه ، در رویدادِ بسته شدنِ برنامه اش ، این لیست را خودش dispose کنه؟
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
یه چیز دیگه اینکه در پنجره و پنل properties (موقع طراحی و در دیزاینر ویژال استودیو) ، وقتی پروپرتی ای را تعریف میکنیم ، در قسمتِ زیرِ همون پنجره ، توضیحاتِ مربوط به همون پروپرتی نوشته میشه که متفاوت با توضیحاتی هست که موقع کدنویسی ، در قسمتِ summery مربوط به اون پروپرتی مینویسیم .
این توضیحات را چجوری میشه برای پروپرتی ای که خودمون در کلاس مون خلق میکنیم ، اضافه کنیم تا این توضیحات را در همون قسمت زیر پنل properties (در دیزاینر ویژال استودیو) نمایش بده؟


بعد اینکه اگه یه شی ای کلاسی داشته باشیم (مثلا شی ای از TransparentControlText) ، که هیچ شی ای از هیچ کلاس دیگه ای بهش اشاره نکنه اما یکی از اعضای این کلاس (پروپرتیِ TransparentControl که درون کلاس TransparentControlText هست) به یه شی کلاس دیگه (به شی کلاس TransparentControlText) اشاره کنه ، در این صورت ، باز چون هیچ اشاره گری به شیِ این کلاسِ TransparentControlText وجود نداره ، GC هر وقت بخواد میتونه شیِ TransparentControlText را نابود کنه دیگه؟ درسته؟
 

the_king

مدیرکل انجمن
آها.
خیلی ممنون استاد.
پس اگه اشتباه نکنم ، منظورتون اینه که فقط اشیاء هایی که (dispose شدنی هست و) فقط اولا خودم ساختم (نه اینکه شیِ dispose شدنی ای که از برنامه نویس دریافت کردم) و دوما شی جدیدی برایش در نظر گرفتم (new کردم) (نه هر شی ای که از کنترل یا جاهای دیگه مثل همون قضیه ی فونت والد ای که گفتم ، گرفته باشم) را در لیست dispose بذارم
تا اینجا درسته.
و هر وقت کنترل ام dispose شد ، یا شیِ قبلیِ مربوطه ، null شد ، اون شیِ مورد نظر را dispose کنم.
منظورتون همین هه . درست میگم؟
هر وقت کنترل تون Dispose شد فقط چیزی رو Dispose کنید که خود کنترل ساخته. اگر کنترل تون TransparentControl باشه و شیء ای رو در TransparentControlText ساختید، Dispose کردن اون شیء وظیفه کنترل شما نیست، باید وقتی Dispose بشه که TransparentControlText ئه Dispose میشه، نه TransparentControl ئه.

اما باز یک مسئله پیش میاد.
اینکه اشیاءهای dispose شدنی که ممکنه مشترکا استفاده شده باشن (مثل همون فونت کنترل والد) یا اصلا مشترکا استفاده نشده باشن و ما نمیدونیم (مثلا شیِ dispose شدنی ای که برنامه نویس داده باشه اما اگه اشتباه نکنم ، شما در بالا گفتین که هر چی کاربر شی dispose شدنی رو میده ، dispose نکنم) را چی کار کنم؟
کاری به اونها ندارید، چیزی که برنامه نویس ساخته یا Designer ساخته رو خودشون مسئولش هستند، نه شما. شما نمی توانید تشخیص بدهید که چه زمانی لازمه که اونها Dispose بشه، دخالتی هم نمی کنید.
مثلا اون دکمه ای که روی فرم هست و یا فونت پیشفرض فرم رو کد ایجادش رو شما ننوشته اید و شما هم نباید Dispose کنید.

از طرفی هم خودتون گفتین که هر شی dispose شدنی ، بهتره برای آزاد کردن حافظه ی unmanaged اش (و حتی حافظه ی managed اش) ، dispose و آزاد بشه.
نمیفهمم چی می گید یا منظورتون چیه، بهتره رو کجا در حرف های من دیدید؟ درضمن Dispose اصولا کاری به منابع Managed نداره، چون مربوط به GC ئه. اگر Dispose کاری در مورد منابع Managed انجام بده در حد null کردن متغیر یا تغییر وضعیت متغیر خاصی است که فرضا بشه فهمید این شیء Dispose شده. آزاد کردن منابع Managed رو کجا دیدید که من ربط بدم به Dispose ؟ ما بهتر و بدتر و یکم بد و خوب هم نداریم، یا کاری باید انجام بشه یا لازم نیست انجام بشه. آزاد کردن منابع Unmanaged باید حتما انجام بشه و برای انجامش یا مستقیما یا با واسطه Dispose میشه یا بجایش از using استفاده میشه.

خوب ، تکلیف این نوع اشیاءهایی که dispose شدنی اند (و خیلی هم ممکنه باشند . چه اونهایی که توی شی قبلی استفاده شدند و با تعویض شی ، dispose نشدند و ...) و سر آخر ، کاربر نهایی بخواد نرم افزار و برنامه ای که این کنترل مون در اون استفاده شد را ببنده و این همه اشیاء dispose شدنی ای که dispose نشدند ، چی میشه؟
از اونجایی که بجز ایجاد کننده شیء شخص دیگری نمیدونه روال مد نظر طراح چیه و نمیتونه تصمیم بگیره که کی وقت مناسب Dispose شدنه، باید خود سازنده شیء برای Dispose شدن اقدام کنه. اگر شیء ای رو شما ایجاد نکردید، به Dispose شدنش کاری ندارید.

پس بهتر نیست ، علاوه بر راهکاری که در بالا دادین (پاراگراف اول که گفتم) ، یه لیست static ای از این نوع اشیاء های dispose شدنی (که برنامه نویس میده یا ما از کنترل های دیگه استفاده میکنیم) در نظر بگیریم تا برنامه نویس وقتی میخواد برنامه اش بسته بشه ، در رویدادِ بسته شدنِ برنامه اش ، این لیست را خودش dispose کنه؟
نه. هر شیء که منابع Unmanaged داره و استفاده ای نداره باید در اولین فرصت آزاد بشه، نه زمانی که برنامه اجراش تموم میشه. از طرف دیگه بسته شدن برنامه لزوما به این معنی نیست که باید همه منابع مدیریت نشده آزاد بشه، شاید منبعی که تخصیص داده شده، بین چند برنامه مشترک مورد استفاده قرار گرفته و فعلا که سایر برنامه ها دارند ازش استفاده می کنند، دلیلی برای آزاد کردنش نباشه.
 

the_king

مدیرکل انجمن
سلامی مجدد
یه چیز دیگه اینکه در پنجره و پنل properties (موقع طراحی و در دیزاینر ویژال استودیو) ، وقتی پروپرتی ای را تعریف میکنیم ، در قسمتِ زیرِ همون پنجره ، توضیحاتِ مربوط به همون پروپرتی نوشته میشه که متفاوت با توضیحاتی هست که موقع کدنویسی ، در قسمتِ summery مربوط به اون پروپرتی مینویسیم .
این توضیحات را چجوری میشه برای پروپرتی ای که خودمون در کلاس مون خلق میکنیم ، اضافه کنیم تا این توضیحات را در همون قسمت زیر پنل properties (در دیزاینر ویژال استودیو) نمایش بده؟
صفت Description برای اینکار است.

بعد اینکه اگه یه شی ای کلاسی داشته باشیم (مثلا شی ای از TransparentControlText) ، که هیچ شی ای از هیچ کلاس دیگه ای بهش اشاره نکنه اما یکی از اعضای این کلاس (پروپرتیِ TransparentControl که درون کلاس TransparentControlText هست) به یه شی کلاس دیگه (به شی کلاس TransparentControlText) اشاره کنه ، در این صورت ، باز چون هیچ اشاره گری به شیِ این کلاسِ TransparentControlText وجود نداره ، GC هر وقت بخواد میتونه شیِ TransparentControlText را نابود کنه دیگه؟ درسته؟
بله، اینکه فیلد های داخل یک شیء مقداری داشته باشند یا نه روی نابود کردن شیء تاثیری نداره.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد.
بعد بهتر نیست که کنترل TransparentControl ، زمانی که dispose شد ، من اون رو از کنترل والدش Remove هم کنم؟
یعنی :
کد:
this.Parent.Controls.Remove(this);
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
کاری به اونها ندارید، چیزی که برنامه نویس ساخته یا Designer ساخته رو خودشون مسئولش هستند، نه شما. شما نمی توانید تشخیص بدهید که چه زمانی لازمه که اونها Dispose بشه، دخالتی هم نمی کنید.
مثلا اون دکمه ای که روی فرم هست و یا فونت پیشفرض فرم رو کد ایجادش رو شما ننوشته اید و شما هم نباید Dispose کنید.

خیلی ممنون استاد.
الان یعنی اگه یه پروپرتیِ dispose شدنی ای ، مقدار داشت (مقدار جدید بهش دادم) ، بعد ، مقدارش عوض شد (مقدار عوض شده ، چه میخواد null باشه یا یه شیِ دیگه) ، همون زمان که شی اش عوض میشه ، شیِ قبلی اش را dispose نکنم ؟
الان شما میگید ، همه ی شی های جدیدی که خودم بهشون میدم را توی همون لیست بذارم و فقط و فقط اگه متد dispose اش اجرا شد ، همه ی اون اشیاءها را dispose کنم؟
آخه گفته بودید در اولین فرصتی که به شی اش نیازی نیست (زمانی که مقدارش عوض میشه ، به مقدار قبلی نیازی نیست دیگه) ، باید اون شی dispose بشه.


من توی پروپرتی های dispose شدنی در هر 3 کلاس (زمانی که مقدارش عوض میشه) ، مقدار قبلی را dispose کردم .
بعد از اون ، زمان دیزاینر یه ارورهای عجیب و قریبی میده . اصلا به شی جدید ، کاری ندارم. قبل از اضافه کردنِ کدهای dispose ، این ارورها نبود.
اما موقعی که همون عملیات را بصورت کدنویسی انجام میدم ، اروری نمیده!!
ارورهاش هم مختلف هه ولی اغلب یه ارور کوتاه هه که میگه پارامتر اش invalidate هه . حالا کجا و کدوم پارامتر را نمیگه. باید چیکار کنم؟
الان منظور شما ، روش بالایی بود؟ روش بالایی رو برم؟
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد.
الان یعنی اگه یه پروپرتیِ dispose شدنی ای ، مقدار داشت (مقدار جدید بهش دادم) ، بعد ، مقدارش عوض شد (مقدار عوض شده ، چه میخواد null باشه یا یه شیِ دیگه) ، همون زمان که شی اش عوض میشه ، شیِ قبلی اش را dispose نکنم ؟
الان شما میگید ، همه ی شی های جدیدی که خودم بهشون میدم را توی همون لیست بذارم و فقط و فقط اگه متد dispose اش اجرا شد ، همه ی اون اشیاءها را dispose کنم؟
آخه گفته بودید در اولین فرصتی که به شی اش نیازی نیست (زمانی که مقدارش عوض میشه ، به مقدار قبلی نیازی نیست دیگه) ، باید اون شی dispose بشه.


من توی پروپرتی های dispose شدنی در هر 3 کلاس (زمانی که مقدارش عوض میشه) ، مقدار قبلی را dispose کردم .
بعد از اون ، زمان دیزاینر یه ارورهای عجیب و قریبی میده . اصلا به شی جدید ، کاری ندارم. قبل از اضافه کردنِ کدهای dispose ، این ارورها نبود.
اما موقعی که همون عملیات را بصورت کدنویسی انجام میدم ، اروری نمیده!!
ارورهاش هم مختلف هه ولی اغلب یه ارور کوتاه هه که میگه پارامتر اش invalidate هه . حالا کجا و کدوم پارامتر را نمیگه. باید چیکار کنم؟
الان منظور شما ، روش بالایی بود؟ روش بالایی رو برم؟

استاد ، همونطور که شما گفتین ، فقط موقعی که متد dispose اجرا میشه ، اون اشیاء ها را dispose کردم و مشکل اون ارور برطرف شد.
توی کدهای designer (کدهای Editor) هم لازمه که شی های جدیدی که میذارم را dispose کنم؟
چون دیگه موقع طراحی که نرم افزاری که برنامه نویس نوشت ، اجرا نیست . طرف ، نرم افزار را طراحی میکنه و بعد ویژال استودیو رو میبنده و سیستم را خاموش میکنه که همه ی اطلاعات از حافظه پاک میشه.
 

جدیدترین ارسال ها

بالا