PDA

View Full Version : تفاوت بین using , dispose



hamid_hr
سه شنبه 20 خرداد 1393, 19:32 عصر
ایا بین using و dispose فرقی هست
مثلا بنویسیم


using (System.IO.MemoryStream ms = new ...)
{
...
}


یا



System.IO.MemoryStream ms = new ....

....

ms.Dispose();


این دو تا یک کارو انجام میدن یا نه؟

samin_panahi
چهارشنبه 21 خرداد 1393, 00:23 صبح
dispose متد نابود کننده ست
این لینک (http://barnamenevis.org/showthread.php?453789-this-Dispose%28%29-%DB%8C%D8%B9%D9%86%DB%8C-%DA%86%DB%8C%D8%9F&highlight=Dispose) رو مطالعه کنید

plus
چهارشنبه 21 خرداد 1393, 01:53 صبح
ایا بین using و dispose فرقی هست
مثلا بنویسیم


using (System.IO.MemoryStream ms = new ...)
{
...
}


یا



System.IO.MemoryStream ms = new ....

....

ms.Dispose();


این دو تا یک کارو انجام میدن یا نه؟
کد دومی که ارائه کردین معادل کد اول نیست.در صورتی که بین new و Dispose یک Exception اتفاق بیافته Dispose اجرا نمیشه در صورتی که در using این طور نیست.
این دو کد معادل هستن:

using (MemoryStream ms = new MemoryStream()) {
...
}



MemoryStream ms = null;
try {
ms = new MemoryStream();
...
}
finally {
if (ms != null) {
ms.Dispose();
}
}



در مورد اینکه کدوم بهتره هم، اگه شما نیازی نداشته باشی که Exception های ایجاد شده رو Catch کنی، استفاده از using خلاصه تر هست، ولی در صورتی که نیاز به کنترل Exception های ایجاد شده داشته باشی استفاده از using مناسب نیست چون مجبور میشی یک try..catch دیگه داخل using ی که خودش معادل try...finally هست بگذاری.
در حالت دوم کدی شما با try finally میشه :

MemoryStream ms = null;
try {
ms = new MemoryStream();
...
}
catch (IOException ex) {
Console.WriteLine("An exception occured: " + ex.Message);
}
finally {
if (ms != null) {
ms.Dispose();
}
}

forodo
چهارشنبه 21 خرداد 1393, 11:19 صبح
حالا باید از اینها استفاده کرد یا نه؟
چون خود #C چیزی داره که خودش خود به خود فضاهای اشغال شده رو پاک می کنه (GC).

plus
چهارشنبه 21 خرداد 1393, 12:07 عصر
حالا باید از اینها استفاده کرد یا نه؟
چون خود #C چیزی داره که خودش خود به خود فضاهای اشغال شده رو پاک می کنه (GC).
GC فقط Managed Resources رو آزاد میکنه ولی وقتی یک کلاس، Unmanaged Resources (مثل File Handle و ...) داره، باید IDisposable رو پیادره سازی کنه و در نهایت، استفاده کننده از اون کلاس با استفاده از using یا فراخوانی Dispose باعث میشه Unmanaged Resources آزاد بشه.

البته در مورد مثالی که زدن، MemoryStream منابع مدیریت نشده نداره و احتمالا Dispose نکردن سریح اون مشکلی ایجاد نمیکنه، ولی استفاده از using باعث میشه که این اطمینان وجود داشته باشه که هیچ ارجاعی به اون شی باقی نمیمونه و GC میتونه اون شی رو Collect کنه.
کلا Dispose کردن سریح اشیایی که IDisposable هستن (چه با using چه با try...finally) توصیه میشه.

forodo
چهارشنبه 21 خرداد 1393, 12:47 عصر
GC فقط Managed Resources رو آزاد میکنه ولی وقتی یک کلاس، Unmanaged Resources (مثل File Handle و ...) داره، باید IDisposable رو پیادره سازی کنه و در نهایت، استفاده کننده از اون کلاس با استفاده از using یا فراخوانی Dispose باعث میشه Unmanaged Resources آزاد بشه.
Managed Resources و Unmanaged Resources چیه؟
و لطفاً به این پست (http://barnamenevis.org/showthread.php?453789-this-Dispose%28%29-%DB%8C%D8%B9%D9%86%DB%8C-%DA%86%DB%8C%D8%9F&p=2040650&viewfull=1#post2040650) هم جواب بدید.

plus
چهارشنبه 21 خرداد 1393, 13:15 عصر
Managed Resources و Unmanaged Resources چیه؟
و لطفاً به این پست (http://barnamenevis.org/showthread.php?453789-this-Dispose%28%29-%DB%8C%D8%B9%D9%86%DB%8C-%DA%86%DB%8C%D8%9F&p=2040650&viewfull=1#post2040650) هم جواب بدید.
به طور خلاصه، منظور از Managed Resources (منابع مدیریت شده)، همون Managed Memory یا حافظه مدیریت شده هست که توسط Garbage Collector مدیریت میشه (وقتی هیچ Reference (ارجاع)ی به یک شی نباشه حافظه اون شی آزاد میشه).
Unmanaged Resources هر منبع دیگه ای هست که البته بر خلاف Managed Resources، دیگه Garbage Collector چیزی ازش نمیدونه و نمیتونه مدیریتش کنه.
برای مثال، وقتی شما یک شی رو با استفاده از new ایجاد میکنید، Garbage Collector از حافظه اختصاص داده شده و ارجاهات به اون شی اطلاع داره و به موقع اون رو از حافظه خارج میکنه...در این حالت شما نگران آزاد کردن این منبع به اصطلاح Managed Resource نیستید.
ولی وقتی شما منبع دیگه ای رو در اختیار میگیرین (برای نمونه، ایجاد یک فایل با Windows API) شما مسئول مدیریت و آزاد سازی اون منبع که به اصطلاح Unmanaged Resource هست، میشین.بنابرین کلاسی که این منبع رو در اختیار میگیره و مدیریت میکنه بایستی IDisposable رو پیاده سازی که و در متد Dispose این منابع Unmanaged رو آزاد کنه چون GC نمیتونه این آزاد سازی رو انجام بده.
--
پاسخ اون پست رو هم دوستان دادن، this به شی جاری اشاره میکنه و به طور کلی فراخوانی Dispose باعث میشه که منابع مدیریت نشده اون شی آزاد بشه و البته اون شی دیگه قابل استفاده نخواهد بود.

forodo
چهارشنبه 21 خرداد 1393, 13:30 عصر
به طور خلاصه، منظور از Managed Resources (منابع مدیریت شده)، همون Managed Memory یا حافظه مدیریت شده هست که توسط Garbage Collector مدیریت میشه (وقتی هیچ Reference (ارجاع)ی به یک شی نباشه حافظه اون شی آزاد میشه).
Unmanaged Resources هر منبع دیگه ای هست که البته بر خلاف Managed Resources، دیگه Garbage Collector چیزی ازش نمیدونه و نمیتونه مدیریتش کنه.
برای مثال، وقتی شما یک شی رو با استفاده از new ایجاد میکنید، Garbage Collector از حافظه اختصاص داده شده و ارجاهات به اون شی اطلاع داره و به موقع اون رو از حافظه خارج میکنه...در این حالت شما نگران آزاد کردن این منبع به اصطلاح Managed Resource نیستید.
ولی وقتی شما منبع دیگه ای رو در اختیار میگیرین (برای نمونه، ایجاد یک فایل با Windows API) شما مسئول مدیریت و آزاد سازی اون منبع که به اصطلاح Unmanaged Resource هست، میشین.بنابرین کلاسی که این منبع رو در اختیار میگیره و مدیریت میکنه بایستی IDisposable رو پیاده سازی که و در متد Dispose این منابع Unmanaged رو آزاد کنه چون GC نمیتونه این آزاد سازی رو انجام بده.
--
پاسخ اون پست رو هم دوستان دادن، this به شی جاری اشاره میکنه و به طور کلی فراخوانی Dispose باعث میشه که منابع مدیریت نشده اون شی آزاد بشه و البته اون شی دیگه قابل استفاده نخواهد بود.
خیلی ممنون بابت توضیحاتتون.
پس یعنی اگر شی را با استفاده از new درست کنیم اصلاً کاری به اون شی نداشته باشیم چون فضای اشغال شده توسط اون شی خود به خود آزاد می شه مثل:
ali a = new ali();
SqlConnection con = new SqlConnection();
DataSet ds = new DataSet();
TextBox tb = new TextBox();
PersianCalendar pc = new PersianCalendar();
ولی موقعی که از توابع API استفاده می کنیم خودمون باید فضا رو آزاد کنیم.
درست گفتم؟
................................
نه منظورم در اون پست استفاده از using رو dispose که مثال زدم . اینجا دوباره قرارش می دم.
کدهایی که باید داخل کلاس بنویسیم برای اینکه متد Dispose رو داشته باشیم چیه؟
می دونم باید کلاس رو اینطوری بنویسیم:
class ali : IDisposable




حالا متد dispose کداش چیه؟

و اگر نخوایم از کلاس اینترفیس IDisposable ارث بری کنه، می تونیم توی برنامه اینطوری بنویسیم؟
کلاسی داریم که کداش اینه:


class ali
{
public void alireza()
{
messagebox.show("test");
}
}










حالا که ما توی این کلاس متد dispose نداریم توی برنامه از using استفاده کنیم همون کار رو انجام می ده؟


using (ali a=new ali())
{
a.alireza();
}










الان اینجوری فضای اشغال شده توسط شی a از حافظه کامپیوتر پاک می شه؟

plus
چهارشنبه 21 خرداد 1393, 13:58 عصر
خیلی ممنون بابت توضیحاتتون.
پس یعنی اگر شی را با استفاده از new درست کنیم اصلاً کاری به اون شی نداشته باشیم چون فضای اشغال شده توسط اون شی خود به خود آزاد می شه مثل:
ali a = new ali();
SqlConnection con = new SqlConnection();
DataSet ds = new DataSet();
TextBox tb = new TextBox();
PersianCalendar pc = new PersianCalendar();
ولی موقعی که از توابع API استفاده می کنیم خودمون باید فضا رو آزاد کنیم.
درست گفتم؟

1) اگه کلاس مورد نظر شما IDisposable رو پیاده سازی نکرده باشه، مثل کلاس ali، شما کلا نمیتونید Dispose رو انجام بدین چون چنین متدی اصلا وجود نداره.آزاد سازی رو GC زمانی که خودش تشخیص بده انجام میده.
2) اگه کلاس مورد نظر IDisposable رو پیاده کرده باشه، شما "میتونید" که بعد از اینکه کارتون رو با شی انجام دادین اصلا کاری بهش نداشته باشید.در نهایت GC با تشخیص خودش متد Dispose شی رو فراخوانی میکنه و منابع Unmanaged شی آزاد میشه و حافظه اختصاص داده شده هم که Managed Resource هست باز توسط GC آزاد میشه.
ولی به این نکته توجه کنید که شی ای که ایجاد کردین احتمالا منابع Unmanaged ی رو در اختیار داره که بهتره هرچه زودتر آزاد بشن. (برای مثال یک SqlConnection یک ارتباط با دیتابیس ایجاد کرده) بنابراین که اگه شما دیگه احتیاجی به اون شی ندارین، بهتره که بلافاصله با فراخوانی Dispose (یا استفاده از using) باعث بشین تا "منابع مدیریت نشده" آزاد بشن.
دقت کنید که فراخوانی Dispose باعث نمیشه حافظه Managed اختصاص داده شده به شی همون موقع آزاد بشه.حافظه مدیریت شده، همونطور که از اسمش پیداس توسط GC مدیریت میشه و فازغ از اینکه شما Dispose رو فراخوانی کنید یا نه در زمان غیر قابل پیشبینی آزاد میشه.
درضمن منابع مدیریت نشده لزوما توسط توابع API اختصاص داده نمیشن...


حالا متد dispose کداش چیه؟

در مورد IDisposable میتونید اینجا مطالعه کنید: http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
IDispsable رو به این صورت میشه پیاده کرد:

class MyDisposableClass : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = false;

// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;

if (disposing) {
// Free any other managed objects here.
//
}

// Free any unmanaged objects here.
//
disposed = true;
}
}
همونطور که میبینید دو محل برای ازاد سازی منابع مدیریت شده و مدیریت نشده هست که بایستی توسط کلاس مورد نظر پیاده ب



و اگر نخوایم از کلاس اینترفیس IDisposable ارث بری کنه، می تونیم توی برنامه اینطوری بنویسیم؟
کلاسی داریم که کداش اینه:


class ali
{
public void alireza()
{
messagebox.show("test");
}
}










حالا که ما توی این کلاس متد dispose نداریم توی برنامه از using استفاده کنیم همون کار رو انجام می ده؟


using (ali a=new ali())
{
a.alireza();
}









خیر، کلاس شما اگه IDisposable نباشه نمیتونید اصلا در using قرارش بدین.


الان اینجوری فضای اشغال شده توسط شی a از حافظه کامپیوتر پاک می شه؟

خیر، باز هم میگم، با فراخوانی Dispose یا استفاده از using حافظه اختصاص داده شده به شی (که جزو Managed Resource) هست آزاد نمیشه، فقط منابع مدیریت نشده آزاد میشن.
حافظه اختصاص داده شده به شی در هر صورت توسط GC و در زمان غیر قابل پیش بینی آزاد میشه.

forodo
چهارشنبه 21 خرداد 1393, 14:37 عصر
واقعاً متشکرم که وقت گذاشتید.
الان کاملاً گرفتم چی شد.
فقط یه چیز رو درست متوجه نشدم.
از کجا می شه فهمید منابع مدیریت شده و مدیریت نشده کدوما هستند.
مثلاً گفتید که ارتباط با بانک یه منبع مدیریت نشدست.
بقیه رو از کجا می شه فهمید؟

hamid_hr
چهارشنبه 21 خرداد 1393, 15:42 عصر
من خودم هر شی رو که ایجاد میکنم وقتی کارم باهاش تموم شد اگه متد dispose داشت اجرا میکنم

forodo
چهارشنبه 21 خرداد 1393, 16:53 عصر
من خودم هر شی رو که ایجاد میکنم وقتی کارم باهاش تموم شد اگه متد dispose داشت اجرا میکنم
ایول.
همون قضیه کار از محکم کاری عیب نمی کنه.
پس اگر برای هر کلاس تابع dispose را درست کنیم و همه جای برنامه بعد از تمام شدن کارمون با شی که در اصل می شه آخر بلوکی که شی در اون قرار داشته شی رو dispose کنیم مشکلی پیش نمیاد.
بازم ممنون.