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

the_king

مدیرکل انجمن
آها خیلی ممنون .
ولی همونطور که میدونید ، از این دست اعضایی که به درد یک کلاسِ خاص نمیخوره (که جریانش را در پست قبلی توضیح دادم) و صرفا در ارتباط با View هست که معنا پیدا میکنه ، در طول پروژه ، زیادتر و زیادتر میشن .

در واقع نیازهای معماری MVVM هست که این نیازِ اضافی برای این نوع اعضا را بوجود میاره . (چون در معماری غیر MVVM ، فرضا همون کد در تاپیک wpf ، در همون View بود و لازم به جدا شدن نداشت) .
اگر بخواهید اصول شی گرایی رو رعایت کنید همچنان هر چیزی که مربوط به View هست الزاما یکجا قرار نمیگیره، چه MVVM باشه و چه نباشه. فرضا کپسوله سازی جزو مبانی شی گرایی است، مستقل از اینکه معماری MVVM است یا نیست، در معماری های دیگه هم تفکیک صورت میگیره.
پس به نظرتون چطوره یه کلاس در Model بنام ExteraMemberForMVVM تعریف کنم تا این اعضاهایی که به درد یک کلاس خاصی نمیخوره و صرفا در پروژه ی MVVM (و در کد تاپیک wpf که دادم ، در ارتباط با View) هست که معنا پیدا میکنه را در اون تعریف کنم؟
طراح پروژه شما من نیستم که نظر من رو بپرسید. "اصول برنامه نویسی شی گرا" رو جستجو کنید و مطالعه کنید، می بینید که محتویات کلاس موضوع مشترکی دارند، کلاس یک انباری نیست که هر چیزی که جایی براشون پیدا نمی کنید داخلش بریزید، تفکیک موضوعی مهم ئه.
 

SajjadKhati

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

خیلی ممنون استاد .
اصول برنامه نویسی شی گرا را بلدم .
واسه ی همین این سئوال را مطرح کردم .
الان در یک متد که در تاپیک wpf دادم ، باید برای تولیدِ آرایه ای از رشته های مورد نظر ، ۲ تا متد دیگه در model ایجاد کنم .

حالا در کدوم یک از اون دو کلاسم به این اعضا ربط دارن؟
هیچ کدوم.

هیچ کدوم هم که ربط نداشته باشن ، پس اصول شی گرایی رعایت نشده .

اگه اون دو تا متد (و متدهای دیگه ای در آینده که در ارتباط با mvvm و مثل همین ها که بوجود میاد) را توی کلاس مجزایی هم بذارم ، کلاسی نمیشه که هدف خاصی را دنبال کنه و به قول شما مثل یه انبار میشه (و اصول شی گرایی را که یه شی و هدفی را دنبال کنه ، رعایت نمیکنه) .

از طرفی هم نمیتونم فرضا تا آخرِ پروژه که ۱۰۰ تا از این متدها را خواستم به model ام منتقل کنم ، در ازاش ۱۰۰ تا کلاس بسازم .

پس نهایتا باز هم این سئوال پابرجاست که بهترین راه حل برای این نوع اعضا چیه ؟
اصلا شما باشین ، چی کار میکنین؟
یعنی اون متدی که در تاپیک wpf دادم را بخواین بخشی از متدی که آرایه ای از رشته را تولید میکنه را جدا کنین و به model تون منتقل کنین ، به چه نوع از کلاسِ model تون منتقل میکنید؟
فرضا از متد استاتیک استفاده میکنید یا روش یا کلاس دیگه؟
کلا روش تون چیه برای این راهکار؟

تشکر
 

the_king

مدیرکل انجمن
خیلی ممنون استاد .
اصول برنامه نویسی شی گرا را بلدم .
واسه ی همین این سئوال را مطرح کردم .
الان در یک متد که در تاپیک wpf دادم ، باید برای تولیدِ آرایه ای از رشته های مورد نظر ، ۲ تا متد دیگه در model ایجاد کنم .

حالا در کدوم یک از اون دو کلاسم به این اعضا ربط دارن؟
هیچ کدوم.

هیچ کدوم هم که ربط نداشته باشن ، پس اصول شی گرایی رعایت نشده .

اگه اون دو تا متد (و متدهای دیگه ای در آینده که در ارتباط با mvvm و مثل همین ها که بوجود میاد) را توی کلاس مجزایی هم بذارم ، کلاسی نمیشه که هدف خاصی را دنبال کنه و به قول شما مثل یه انبار میشه (و اصول شی گرایی را که یه شی و هدفی را دنبال کنه ، رعایت نمیکنه) .

از طرفی هم نمیتونم فرضا تا آخرِ پروژه که ۱۰۰ تا از این متدها را خواستم به model ام منتقل کنم ، در ازاش ۱۰۰ تا کلاس بسازم .

پس نهایتا باز هم این سئوال پابرجاست که بهترین راه حل برای این نوع اعضا چیه ؟
اصلا شما باشین ، چی کار میکنین؟
یعنی اون متدی که در تاپیک wpf دادم را بخواین بخشی از متدی که آرایه ای از رشته را تولید میکنه را جدا کنین و به model تون منتقل کنین ، به چه نوع از کلاسِ model تون منتقل میکنید؟
فرضا از متد استاتیک استفاده میکنید یا روش یا کلاس دیگه؟
کلا روش تون چیه برای این راهکار؟

تشکر
اگر اصول برنامه نویسی شیء گرا رو بلد باشید طوری روال ها رو تقسیم می کنید که هر قسمت در بخش مناسب قرار بگیره.
فرضا متدی که حجم رو از بایت به یک واحد دیگه تبدیل می کنه چرا در VssBackup ئه؟ تبدیل حجم از بایت به رشته چه ارتباطی با وظایف VSS داره؟
یا چرا لیست درایو های NTFS رو کلاس ExtensionMethodViewModel میده؟
وقتی هر چیزی رو در جای نامناسبی قرار بدهید طبعا برای ایجاد روال ارتباط های نامناسبی ایجاد می کنید که وابستگی بین بخش هایی بوجود میاره که اساسا بهم ربطی ندارند. فرضا اگر قرار بوده ExtensionMethodViewModel لیست درایو ها رو به View منتقل کنه و واسطه است، باید خروجی اش چیزی باشه که مناسب View ئه. نه DriveInfo مناسب استفاده در View بوده و نه TotalSize اش برای نمایش مناسب بوده. مناسب نبوده که اومده اید بعدش با توسل به VssBackup استخراج داده مناسب View می کنید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
اگر اصول برنامه نویسی شیء گرا رو بلد باشید طوری روال ها رو تقسیم می کنید که هر قسمت در بخش مناسب قرار بگیره.
فرضا متدی که حجم رو از بایت به یک واحد دیگه تبدیل می کنه چرا در VssBackup ئه؟ تبدیل حجم از بایت به رشته چه ارتباطی با وظایف VSS داره؟

سلامی مجدد
خیلی ممنون استاد .
قبلا بعضی از اعضا و متدها را کاملا موقتی نوشتم . صرفا همه شون را توی کلاس VssBackup گذاشته بودم تا بعدا درست کنم . پروژه هنوز تکمیل نشد . مثلا متد GetFixedNtfsDrives که الان به عنوان extension method برای DriveInfo در کلاس ExtensionMethodForDriveInfo منتقل کردم ، قبلا توی کلاس VssBackup بصورت موقت نوشته بودم .

کلاس VssBackup هم و خیلی های دیگه هنوز اعضاش نوشته نشدن (اون اعضایی که نام بردم) . چون الان بیشتر روی ظاهر (و چیدمان کنترل ها) دارم کار میکنم . صرفا فقط اعضایی از منطق تجاری که برای ساخت ظاهر کاربری لازم هست را دارم میسازم .
اصلا بخاطر اینکه الان دارم اعضاشون را مرتب میکنم (تا هر کدوم در جایگاه شون باشن) ، دارم همین سئوال را میپرسم دیگه .



سئوالم هم همینه :
فرضا همین متد تبدیل حجم به واحد داده (گیگا یا ترا یا مگابایت) ، یا اون متد فرمت شده ای که لیستدرایوهای ثابت شده را برمیگردونه ، هر کدوم معمولا یه تک متد یا تک عضوی هستن که کارشون ربطی به هیچ کلاسی که مینویسم نداره .
اگه واسه ی هر کدوم بخوام کلاس درست کنم ، اولا کلاس های تک عضوی (یا نهایتا دو تا سه عضوی) میشن که اولا هدف خاصی را دنبال نمیکنن و دوما تعداد این کلاس ها خیلی زیاد میشه (تا اینجای کار من حداقل 3 تا از این متدها دارم که کار 2 دسته شون مجزاست . بعدا که قطعا زیادتر میشه) .

این مشکلی هست که حتی توی کلاس های متفاوت بذارم (صرف نظر از اینکه تعداد این کلاس ها خیلی بالا میره) ، اصلا هر کدوم از اون کلاس ها ، هدف خاصی را دنبال نخواهند کرد . صرفا فقط یکی دو تا متد یا عضوی دارن که فراخونی میشن .
اگه هم که توی یه کلاس بذارم ، باز هم هدف خاصی را دنبال نمیکنن و به قول شما انبار هم میشه .

واسه ی من حالا این سئوال پیش اومد که شما هم احتمالا با همین مشکلات در پروژه ها تون برخورد کردین که (در View یا هر جای دیگه) ، صرفا به یک متد (یا چند متدی) نیاز داشته باشید که در کلاس هایی که در Model تون طراحی کردین ، مناسب اونجا نباشه .

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

پس راهکار چیه؟
یعنی راهکاری که شما برای این کار در پروژه هاتون استفاده میکنین ، چیه؟


یا چرا لیست درایو های NTFS رو کلاس ExtensionMethodViewModel میده؟

متد FillComboBoxByDriveInfos که در کلاس InteropWithUI هست و این کلاس هم جزء View هست .
از این به بعد به نام کلاس های زیر دقت کنید چون شبیه به هم هستن :
متد GetFixedNtfsDrives در کلاس ExtensionMethodForDriveInfo قرار داره که لیست درایوهای ثابت در کاربر نهایی را بصورت آرایه ای از DriveInfo ها میده .
این کلاس چون Extension Method ای برای کلاس DriveInfo هست ، کلاسِ استاتیک هست .

کلاس ExtensionMethodViewModel (که ViewModel ای برای کلاسِ ExtensionMethodForDriveInfo هست) هم دقیقا متدی با همین نام داره (متد GetFixedNtfsDrives داره) اما منطق تجاری توش نوشته نشد .
این متد (یعنی متد ExtensionMethodViewModel.GetFixedNtfsDrives) ، صرفا متدِ مورد نظر در Model ام ، یعنی متدِ ExtensionMethodForDriveInfo.GetFixedNtfsDrives را فراخونی میکنه و مقدارش را برمیگردونه .

قوانین MVVM رعایت شده دیگه .
مگه مشکلی وجود داره؟

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

بله .
اما رعایتِ MVVM باعث شده که برای اینکه کوچیکترین وابستگی بین View و Model ام بوجود نیاد ، اون بخش از کدهایی که قبلا در View بودن ، باید جدا بشن و برن توی Model.
این جدا سازی ، و این متدی که قراره از View به Model بره ، الزاما و معمولا به کار Model ، مربوط نمیشه (چون قبلا و کلا جزئی از View بوده و به کارِ View مربوط میشه) که این نوع جداسازی ، همین مشکل را برام بوجود میاره که نمیدونم چی کار کنم با این قضیه و اون تیکه کد را کجا دقیقا ببرم؟
هر جا در Model ببرم ، وصله ی ناجور برای اون کلاس هست .
مثل همون تیکه کدی در متد FillComboBoxByDriveInfos که خروجیِ لیست فرمت شده از درایوهای ثابت را میداد .

فرضا اگر قرار بوده ExtensionMethodViewModel لیست درایو ها رو به View منتقل کنه و واسطه است، باید خروجی اش چیزی باشه که مناسب View ئه. نه DriveInfo مناسب استفاده در View بوده

DriveInfo که مشکلی نداره .
جزء Model ام نیست .
جزء دات نت فریم وورک هست که مشکلی نیست .

فقط اطلاعاتِ نام درایو را نبردم و اطلاعاتِ DriveInfo را منتقل کردم چون بعدا ممکنه لازم باشه که در View ، به بعضی از اعضاش هم نیاز داشته باشم . گفتم باز دوباره کاری نشه .
اشکالی هم فکر نکنم برای قضیه ی MVVM باشه . داره مگه؟

و نه TotalSize اش برای نمایش مناسب بوده.

مناسب نبوده که اومده اید بعدش با توسل به VssBackup استخراج داده مناسب View می کنید.

این دو تیکه را دقیقا متوجه نشدم .
اگه منظورتون اینه که کلاس VssBackup ، جای مناسبی برای متد ConvertByteToDataUnit نیست ، تقریبا بله و احتمالا بعدا جا به جاش میکنم (هر چند ، این عضو هم حدودا جزء همین مشکلی میشه گفت هست که مطرح کردم) .

اما اگه منظورتون اینه که ساز و کارِ View ام را جوری باید بچینم که به متد ConvertByteToDataUnit اصلا نیازی نداشته باشم ، ربط خاصی نداره . من به خروجی این متد نیاز دارم .
کلا دقیقا متوجه نشدم منظور این تیکه تون را .

تشکر استاد .
 

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد .
قبلا بعضی از اعضا و متدها را کاملا موقتی نوشتم . صرفا همه شون را توی کلاس VssBackup گذاشته بودم تا بعدا درست کنم.
اگر قرار باشه بعدا درست کنید که میشه ساختمونی که جای ستون هاش اشتباه بوده و بعدا که رسیدید به طبقه پنجم تازه میخواهید درستش کنید. اگر قراره یک کد شیء گرا بنویسید باید از همون اول اصول شی گرایی رو رعایت کنید.

پروژه هنوز تکمیل نشد . مثلا متد GetFixedNtfsDrives که الان به عنوان extension method برای DriveInfo در کلاس ExtensionMethodForDriveInfo منتقل کردم ، قبلا توی کلاس VssBackup بصورت موقت نوشته بودم.
کلاس VssBackup هم و خیلی های دیگه هنوز اعضاش نوشته نشدن (اون اعضایی که نام بردم) . چون الان بیشتر روی ظاهر (و چیدمان کنترل ها) دارم کار میکنم . صرفا فقط اعضایی از منطق تجاری که برای ساخت ظاهر کاربری لازم هست را دارم میسازم .
اصلا بخاطر اینکه الان دارم اعضاشون را مرتب میکنم (تا هر کدوم در جایگاه شون باشن) ، دارم همین سئوال را میپرسم دیگه .

سئوالم هم همینه :
فرضا همین متد تبدیل حجم به واحد داده (گیگا یا ترا یا مگابایت) ، یا اون متد فرمت شده ای که لیستدرایوهای ثابت شده را برمیگردونه ، هر کدوم معمولا یه تک متد یا تک عضوی هستن که کارشون ربطی به هیچ کلاسی که مینویسم نداره .
اگه واسه ی هر کدوم بخوام کلاس درست کنم ، اولا کلاس های تک عضوی (یا نهایتا دو تا سه عضوی) میشن که اولا هدف خاصی را دنبال نمیکنن و دوما تعداد این کلاس ها خیلی زیاد میشه (تا اینجای کار من حداقل 3 تا از این متدها دارم که کار 2 دسته شون مجزاست . بعدا که قطعا زیادتر میشه) .
این مشکلی هست که حتی توی کلاس های متفاوت بذارم (صرف نظر از اینکه تعداد این کلاس ها خیلی بالا میره) ، اصلا هر کدوم از اون کلاس ها ، هدف خاصی را دنبال نخواهند کرد . صرفا فقط یکی دو تا متد یا عضوی دارن که فراخونی میشن .
کد NET. رو با ابزار های مربوطه بررسی کنید، انواع کلاس ها رو پیدا می کنید که فقط یکی دو عضو دارند، چه مشکلی دارند؟ هیچی. ثانیا کلاسی که وظیفه اش تبدیل واحد حجم ئه وظیفه خاصی رو دنبال نمی کنه؟ باید چیکار کنه که هدف خاصی محسوب بشه؟ وظیفه اش تبدیل واحد ئه دیگه.
واسه ی من حالا این سئوال پیش اومد که شما هم احتمالا با همین مشکلات در پروژه ها تون برخورد کردین که (در View یا هر جای دیگه) ، صرفا به یک متد (یا چند متدی) نیاز داشته باشید که در کلاس هایی که در Model تون طراحی کردین ، مناسب اونجا نباشه .
مشکلی به عنوان کلاسی که فقط یکی دو عضو داره وجود نداره، کلاس n تا عضو داره، تعدادش به کارکردش بستگی داره. n دو تا باشه چه مشکلی پیش میاد؟
اون یک متد را چی کار میکنین؟
به سادگی اون یک متد رو در کلاسی با نام مناسب قرار می دهم، لزومی هم نمی بینم که از تنهایی خارج اش کنم، قطعا متد های #C از تنها بودن ناراحت نمیشن. قانون مالیات بر کلاس ها هم نداریم که از بابت زیاد شدنشون زیانی متحمل بشویم.
در کلاسِ Model تون (فرضا مثل همین VssBackup) که بهش ربطی نداره که توش جا بدین .
بخواین هم جداش کنین ، توی هر کلاسی بذارین ، اون کلاس ، هدف خاصی را دنبال نخواهد کرد .
از دید شما هدف خاصی رو دنبال نخواهد کرد، ولی ربطی به اصول برنامه نویسی نداره. از دید شما طراحان NET. کلاس هایی ساخته اند که هدف خاصی رو دنبال نمی کنند. ولی از دید اون طراحان هر کدوم از اون کلاس ها هدفی دارند. اون کسی که
System.Net.Comparer
MS.Internal.Printing.Configuration.UnitConverter
System.Windows.Forms.TableLayoutSettings.StyleConverter
System.Windows.Automation.ScrollItemPatternIdentifiers
MS.Internal.Printing.Configuration.SafeModuleHandle
رو طراحی کرده نه تعداد اعضاء کلاس برایش مهم بوده و نه یکی دو تا عضو بودن رو مشکل میدونسته.
صرفا کلاسی میشه که فقط اون عضو توش قرار گرفته تا فراخونی بشه (که در این صورت فرقی نداره که توی اون کلاس باشه یا در کلاسی مثل VssBackup و ...) چون در هر کجا که قرار بگیره ، اون کلاس ، بخاطر اون عضو ، هدفی را دنبال نمیکنه .
تعابیری که شما بکار می برید ربطی به اصول برنامه نویسی شیء گرا ندارند، شما برای خودتون یک معیار های خوب و بد در نظر گرفته اید که شخصی اند، خاص شما هستند. اون مصداقی که شما برای هدف کلاس در نظر گرفته اید تو دکان هیچ عطاری پیدا نمیشه.
پس راهکار چیه؟
یعنی راهکاری که شما برای این کار در پروژه هاتون استفاده میکنین ، چیه؟
اول برای خودتون تعریف مشکل می کنید، بعد گیر می کنید تو مشکل خود ساخته تون.
کلاس System.Windows.Forms.VisualStyles.VisualStyleElement.Taskbar.BackgroundRight
حتی یک متد هم نداره، فقط یک مشخصه فقط خواندنی داره، هدف مشخصی داره، مشکلی هم نداره. طراحانش برای مشکلی که وجود نداره هم دنبال راهکار نگشتند.
متد FillComboBoxByDriveInfos که در کلاس InteropWithUI هست و این کلاس هم جزء View هست .
از این به بعد به نام کلاس های زیر دقت کنید چون شبیه به هم هستن :
متد GetFixedNtfsDrives در کلاس ExtensionMethodForDriveInfo قرار داره که لیست درایوهای ثابت در کاربر نهایی را بصورت آرایه ای از DriveInfo ها میده .
این کلاس چون Extension Method ای برای کلاس DriveInfo هست ، کلاسِ استاتیک هست .

کلاس ExtensionMethodViewModel (که ViewModel ای برای کلاسِ ExtensionMethodForDriveInfo هست) هم دقیقا متدی با همین نام داره (متد GetFixedNtfsDrives داره) اما منطق تجاری توش نوشته نشد .
این متد (یعنی متد ExtensionMethodViewModel.GetFixedNtfsDrives) ، صرفا متدِ مورد نظر در Model ام ، یعنی متدِ ExtensionMethodForDriveInfo.GetFixedNtfsDrives را فراخونی میکنه و مقدارش را برمیگردونه .

قوانین MVVM رعایت شده دیگه .
مگه مشکلی وجود داره؟
شما باید کلاس ExtensionMethodViewModel رو در جایی بکار ببرید که میخواد با واسطه از Model استفاده کنه، یعنی داخل View. خود ViewModel که نیازی به ExtensionMethodViewModel نداره، پس اگر قراره استفاده از ExtensionMethodViewModel در داخل View باشه، چرا باید DriveInfo ای رو به View تحویل بده که به شکل فعلی اش قابل استفاده در View نیست و تازه بعدش می خواهید با VssBackup پردازش اش کنید؟ اگر DriveInfo به شکل فعلی اش مناسب View باشه باید بدون پردازش اضافی ازش استفاده کنه، که اینطور نیست، پس نباید DriveInfo رو به View منتقل می کردید.
بله .
اما رعایتِ MVVM باعث شده که برای اینکه کوچیکترین وابستگی بین View و Model ام بوجود نیاد ، اون بخش از کدهایی که قبلا در View بودن ، باید جدا بشن و برن توی Model.
این جدا سازی ، و این متدی که قراره از View به Model بره ، الزاما و معمولا به کار Model ، مربوط نمیشه (چون قبلا و کلا جزئی از View بوده و به کارِ View مربوط میشه) که این نوع جداسازی ، همین مشکل را برام بوجود میاره که نمیدونم چی کار کنم با این قضیه و اون تیکه کد را کجا دقیقا ببرم؟
تا جایی که به سوال و جواب های برنامه نویسی مربوط بود براتون توضیح دادم. نه پیشبینی می کنم که در آینده می خواهید از DriveInfo در چه جاهایی استفاده بکنید و نه تمایلی دارم که کد شما رو ویراستاری کنم. این شما هستید که تصمیم میگیرید چه چیزی در چه جایی لازمه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
اگر قرار باشه بعدا درست کنید که میشه ساختمونی که جای ستون هاش اشتباه بوده و بعدا که رسیدید به طبقه پنجم تازه میخواهید درستش کنید. اگر قراره یک کد شیء گرا بنویسید باید از همون اول اصول شی گرایی رو رعایت کنید.

سلامی مجدد
خیلی ممنون استاد .
من اول UI را ساختم (هنوز هم تکمیل نشد) .
اون جاهایی که نیاز به متدهایی داشتم که UI ام را کامل کنم (مثلا کمبوباکسی که قرار بود لیست درایوهای ثابت را لیست کنه) ، صرفا فقط برای اونها ، متد و اعضای مورد نظر را اون موقع نوشته بودم .
گفتم هم موقتا کجا بذارم ، حالا توی اون کلاس گذاشتم .
الان هم دارم اعضاش را جا به جا میکنم .
حالا مهم نیست که . پروژه هنوز تکمیل نشد که فرضا بگیم تکمیل شده هست و این مشکل را داره .

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

مشکلی به عنوان کلاسی که فقط یکی دو عضو داره وجود نداره، کلاس n تا عضو داره، تعدادش به کارکردش بستگی داره. n دو تا باشه چه مشکلی پیش میاد؟

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

از دید شما هدف خاصی رو دنبال نخواهد کرد، ولی ربطی به اصول برنامه نویسی نداره. از دید شما طراحان NET. کلاس هایی ساخته اند که هدف خاصی رو دنبال نمی کنند. ولی از دید اون طراحان هر کدوم از اون کلاس ها هدفی دارند. اون کسی که
System.Net.Comparer
MS.Internal.Printing.Configuration.UnitConverter
System.Windows.Forms.TableLayoutSettings.StyleConverter
System.Windows.Automation.ScrollItemPatternIdentifiers
MS.Internal.Printing.Configuration.SafeModuleHandle
رو طراحی کرده نه تعداد اعضاء کلاس برایش مهم بوده و نه یکی دو تا عضو بودن رو مشکل میدونسته.

تعابیری که شما بکار می برید ربطی به اصول برنامه نویسی شیء گرا ندارند، شما برای خودتون یک معیار های خوب و بد در نظر گرفته اید که شخصی اند، خاص شما هستند. اون مصداقی که شما برای هدف کلاس در نظر گرفته اید تو دکان هیچ عطاری پیدا نمیشه.

اول برای خودتون تعریف مشکل می کنید، بعد گیر می کنید تو مشکل خود ساخته تون.
کلاس System.Windows.Forms.VisualStyles.VisualStyleElement.Taskbar.BackgroundRight
حتی یک متد هم نداره، فقط یک مشخصه فقط خواندنی داره، هدف مشخصی داره، مشکلی هم نداره. طراحانش برای مشکلی که وجود نداره هم دنبال راهکار نگشتند.

آها .
خیلی ممنون استاد .
با این مثال هایی که زدید ، بهتر متوجه شدم استاد .
پس در مواقع مورد نیاز ، کلاسی میسازم که حتی یه عضو هم داشته باشه (هر چند تعدادش شاید خیلی زیاد بشه :) ) .

هر چند باز هم بعضی از اون کلاس ها که نام بردید ، یه هدف خاصی را دنبال میکردن . فرضا اینترفیسی را پیاده سازی میکردن .
ولی به هر حال تعداد این نوع کلاس ها زیاد نیست .
هر چند ، متوجه ی قضیه شدم .

شما باید کلاس ExtensionMethodViewModel رو در جایی بکار ببرید که میخواد با واسطه از Model استفاده کنه، یعنی داخل View.

همین کار را میکنم دیگه .
اون متدِ FillComboBoxByDriveInfos ، درون لایه ی View هست .

خود ViewModel که نیازی به ExtensionMethodViewModel نداره، پس اگر قراره استفاده از ExtensionMethodViewModel در داخل View باشه، چرا باید DriveInfo ای رو به View تحویل بده که به شکل فعلی اش قابل استفاده در View نیست و تازه بعدش می خواهید با VssBackup پردازش اش کنید؟

اگر DriveInfo به شکل فعلی اش مناسب View باشه باید بدون پردازش اضافی ازش استفاده کنه، که اینطور نیست، پس نباید DriveInfo رو به View منتقل می کردید.

پروپرتیِ DriveInfo.Name فقط در کمبوباکس به نمایش در اومده .
اما گفتم DriveInfo شامل بقیه ی اطلاعاتی (مثل حجم درایو و ...) هست که احتمال اینکه بعدا در View ازش استفاده کنم ، زیاده و دیگه اطلاعاتش در دسترسم باشه .
حالا شاید هم این اتفاق نیفته .

ولی بالاخره DriveInfo که جزء لایه ی Model ام نیست .
اون کلاس اکستنشن متدی هم که در Model برای DriveInfo نوشتم را بصورت مستقیم از View بهش دسترسی ندارم (توسط ViewModel این کار را انجام میدم) .

بعدش با VssBackup پردازشش نمیکنم . اون متد ConvertByteToDataUnit در VssBackup را به یه کلاس دیگه منتقل میکنم .
اون بخشی از کدهایی در متد FillComboBoxByDriveInfos که لیست فرمت شده از درایوهای ثابت را برمیگردونه را بصورت متدی در کلاس ExtensionMethodForDriveInfo ذخیره میکنم .
صبر کنین ، کلا تکمیل نشد . دنیایی کار دارن .

تا جایی که به سوال و جواب های برنامه نویسی مربوط بود براتون توضیح دادم. نه پیشبینی می کنم که در آینده می خواهید از DriveInfo در چه جاهایی استفاده بکنید و نه تمایلی دارم که کد شما رو ویراستاری کنم. این شما هستید که تصمیم میگیرید چه چیزی در چه جایی لازمه.

بله .
متوجه شدم .
خیلی ممنون استاد .:rose:
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
استاد ، میگم در پنجره ی Diagnostic Tools :


1.JPG

چرا اطلاعات قسمت Process Memory ، با اطلاعاتِ ستونِ Heap Size ئه snapshot ای که در بخش Memory Usage گرفتیم ، با هم اون همه اختلاف دارن؟!

Process Memory میگه برنامه ام تا اون لحظه ، 98 مگابایت از حافظه را اشغال میکنه .
اما snapshot ئه دومی (که تقریبا در همون لحظه گرفته شد) ، ستونِ Heap Size اش میگه برنامه ام از 8.3 مگابایت استفاده میکنه .
این همه تفاوت ، برای چیه؟


و هم اینکه کتابخونه هایی که از حافظه های unmanaged هم استفاده میکنن (ما ، بصورت مستقیم ، از حافظه ی unmanaged در برنامه مون استفاده نمیکنیم . بلکه صرفا اون کتابخونه هایی که ازشون استفاده میکنیم ، اونها در دل خودشون از حافظه های unmanaged استفاده کنن) ، این نوع حافظه ها هم اطلاعات میزان استفاده از حافظه شون ، شامل در این snapshot ها میشه؟

حالا اگه بیایم و ما خودمون مستقیما از حافظه ی unmanaged در کدمون استفاده کنیم ، چی؟ در این صورت هم اطلاعات این snapshot ها ، شامل اطلاعات میزان اشغال حافظه های unmanaged مون ، میشن؟

همچنین ، میشه بجای اینکه در snapshot ها ، دنبالِ همه ی اشیایی که از یک نوع استفاده میکنن ، بگردیم (که همه ی اشیا از یک نوعی که در کل برنامه مون وجود داره ، چقدر حافظه را اشغال کردن) ، بجاش ، صرفا دنبال یک متغییری بگردیم تا ببینیم که اون متغییرمون ، چه مقدار از حافظه را اشغال کرده؟ شدنی هست؟ اگه آره ، لینک منبعِ این قضیه یا توضیحی در این باره میدید؟

تشکر استاد .
 

the_king

مدیرکل انجمن
سلامی مجدد
استاد ، میگم در پنجره ی Diagnostic Tools :


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

چرا اطلاعات قسمت Process Memory ، با اطلاعاتِ ستونِ Heap Size ئه snapshot ای که در بخش Memory Usage گرفتیم ، با هم اون همه اختلاف دارن؟!

Process Memory میگه برنامه ام تا اون لحظه ، 98 مگابایت از حافظه را اشغال میکنه .
اما snapshot ئه دومی (که تقریبا در همون لحظه گرفته شد) ، ستونِ Heap Size اش میگه برنامه ام از 8.3 مگابایت استفاده میکنه .
این همه تفاوت ، برای چیه؟
قرار نبوده یکسان باشند، وقتی دو معیار متفاوت رو با هم مقایسه کنید مقدارشون هم میتونه متفاوت باشه.
و هم اینکه کتابخونه هایی که از حافظه های unmanaged هم استفاده میکنن (ما ، بصورت مستقیم ، از حافظه ی unmanaged در برنامه مون استفاده نمیکنیم . بلکه صرفا اون کتابخونه هایی که ازشون استفاده میکنیم ، اونها در دل خودشون از حافظه های unmanaged استفاده کنن) ، این نوع حافظه ها هم اطلاعات میزان استفاده از حافظه شون ، شامل در این snapshot ها میشه؟
در بحث حافظه پروسه چیزی به نام حافظه مدیریت شده و نشده نداریم، حافظه پروسه مربوط به سیستم عامل ئه که مستقل از NET. ئه. در سایر موارد مثل اون Heap Size، معیار حافظه برنامه در ماشین مجازی ئه، حافظه مدیریت شده است.
حالا اگه بیایم و ما خودمون مستقیما از حافظه ی unmanaged در کدمون استفاده کنیم ، چی؟ در این صورت هم اطلاعات این snapshot ها ، شامل اطلاعات میزان اشغال حافظه های unmanaged مون ، میشن؟
حافظه مدیریت نشده ای که به پروسه برنامه تخصیص می دهید طبعا بخشی از حافظه پروسه است، اما در آمار حافظه مدیریت شده برنامه مثل Heap Size نیست.
همچنین ، میشه بجای اینکه در snapshot ها ، دنبالِ همه ی اشیایی که از یک نوع استفاده میکنن ، بگردیم (که همه ی اشیا از یک نوعی که در کل برنامه مون وجود داره ، چقدر حافظه را اشغال کردن) ، بجاش ، صرفا دنبال یک متغییری بگردیم تا ببینیم که اون متغییرمون ، چه مقدار از حافظه را اشغال کرده؟ شدنی هست؟ اگه آره ، لینک منبعِ این قضیه یا توضیحی در این باره میدید؟
متغیر یک مفهوم داخل زبانی است، در اون snapshot مفهومش رو از دست داده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
قرار نبوده یکسان باشند، وقتی دو معیار متفاوت رو با هم مقایسه کنید مقدارشون هم میتونه متفاوت باشه.

خیلی ممنون استاد .
در توضیحات Process Memory نوشته که
"حافظه ی شخصی اختصاص داده شده به پروسه . شامل heap ، stack و حافظه ی مجازی . بجز حافظه ای که با پروسه های دیگه ، به اشتراک گذاری شده هست" .


پس این که تقریبا مشخص هست .
اما Heap Size ، حداقل مگه بخش بزرگی از حافظه ای که به برنامه اختصاص داده میشه ، نیست؟
من آخر قضیه ی حافظه ی Heap را متوجه نشدم .
الان در شکل پست قبلی که ستون Heap Size داره ، دقیقا منظورش چیه؟
در واقع ، وقتی از حافظه ی Heap حرف میزنه ، از چه چیزی داره حرف میزنه؟
سئوال مهم ام اینه که چرا اون حافظه ی Heap ئه برنامه ، این همه اختلاف با Process Memory داره؟
یه کم توضیح بیشتر یا منبعی در این رابطه میدین؟


در بحث حافظه پروسه چیزی به نام حافظه مدیریت شده و نشده نداریم، حافظه پروسه مربوط به سیستم عامل ئه که مستقل از NET. ئه.

آها خیلی ممنون .

در سایر موارد مثل اون Heap Size، معیار حافظه برنامه در ماشین مجازی ئه، حافظه مدیریت شده است.

حافظه مدیریت نشده ای که به پروسه برنامه تخصیص می دهید طبعا بخشی از حافظه پروسه است، اما در آمار حافظه مدیریت شده برنامه مثل Heap Size نیست.

آره .
منتها در لینک زیر ، یه همچین چیزی نوشته :


The name of the columns depend on the debugging mode you choose in the project properties: .NET, native, or mixed (both .NET and native).

نمیدونم دقیقا منظورش چیه .
اگه منظورش اینه که نام ستون (ستون Managed Object) ، بستگی به debugging mode ای که در پنجره ی Properties ئه پروژه تون انتخاب میکنید (که یا .Net یا native یا هر دوشون میتونن باشن) ، داره ؛ من همچین گزینه ای در پنجره ی Properties ئه پروژه ام ندیدم .
صرفا در پنجره ی debug اش ، گزینه ای بنام "enable native code debugging" دیدم که با فعال کردنش ، فرقی در نام این ستون و همچنین در عنوان پنجره ی snapshot (که در قسمت بالای این پنجره ، عنوانش با Managed Memory شروع میشه) ، نکرد .

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

انگار متوجه شدم یه جورایی .
وقتی در پنجره ی snapshot (عکس زیر در لینک زیر) :



memuse__snapshotdetails_managedheaptree.png


البته در نسخه ی ویژال استودیو 2019 این جوری هه که وقتی رویِ نامِ اون نوع دابل کلیک کنیم (مثل نوع SDKTemplate.MainPage در شکل بالا) ، به صفحه ی جدیدی منتقل میشه که تمام اشیاءِ اون نوع را لیست میکنه .

اما بدیش اینه که مثل تصویر بالا ، نام شی ها را بجای اینکه نام متغییرشون را بنویسه ، شی را بصورت عدد شونزده دهی مینویسه که نمیشه متوجه شد دقیقا کدوم شی هست (هر چند نام شیِ متغییر محلی را در کلوشه ، local variable مینویسه) .

تشکر استاد .
 

the_king

مدیرکل انجمن
اما Heap Size ، حداقل مگه بخش بزرگی از حافظه ای که به برنامه اختصاص داده میشه ، نیست؟
بر چه اساسی این رو میگید؟ هر برنامه ای مشخصات خودش رو داره و با نسبت های متفاوت میان حجم اجزاء اش.
من آخر قضیه ی حافظه ی Heap را متوجه نشدم .
الان در شکل پست قبلی که ستون Heap Size داره ، دقیقا منظورش چیه؟
منظورش حجم فعلی Heap در ماشین مجازی است که به اون برنامه اختصاص داده شده.
در واقع ، وقتی از حافظه ی Heap حرف میزنه ، از چه چیزی داره حرف میزنه؟
از حافظه Heap در ماشین مجازی NET. حرف میزنه، حافظه ای که GC مسئول مدیریتشه.
سئوال مهم ام اینه که چرا اون حافظه ی Heap ئه برنامه ، این همه اختلاف با Process Memory داره؟
چون دو تا مفهوم متفاوت هستند، مثل اینه که بگید چرا وزن شاسی پیکان با وزن خودرو پیکان این همه اختلاف داره.
یه کم توضیح بیشتر یا منبعی در این رابطه میدین؟
در مورد GC و Managed Heap جستجو کنید.
اگه منظورش اینه که نام ستون (ستون Managed Object) ، بستگی به debugging mode ای که در پنجره ی Properties ئه پروژه تون انتخاب میکنید (که یا .Net یا native یا هر دوشون میتونن باشن) ، داره ؛ من همچین گزینه ای در پنجره ی Properties ئه پروژه ام ندیدم .
صرفا در پنجره ی debug اش ، گزینه ای بنام "enable native code debugging" دیدم که با فعال کردنش ، فرقی در نام این ستون و همچنین در عنوان پنجره ی snapshot (که در قسمت بالای این پنجره ، عنوانش با Managed Memory شروع میشه) ، نکرد .
 

SU-57

Active Member
سلام استاد علی

1- من روی فرم یک Button ایجاد می کنم و بعد روی Button دوبار کلیک می کنم و رویداد button1_Click به صورت کامل ایجاد می شه. بعد من میگم اشتباه کردم می خوام یک رویداد دیگه ایجادکنم این رویداد رو به طور کامل انتخاب می کنم و حذف می کنم. بعد که میرم روی فرم می بینم فرم خراب شده. دوباره که میام undo می کنم و اون رویداد ایجاد می شه فرم درست می شه. خوب من نمی خوام رویدادی که برای اون دکمه ایجاد کردم دیگه اونجا باشه و می خوام یک رویداد جدید بذارم و می خوام اون کد رویداد اشتباهی رو حذف کنم اما نمی شه. راهش اینه اول Button حذف کنم و بعدا رویدادش رو حذف کنم اینجوری فرم خراب نمی شه. علتش چیه Visual Studio نمیذاره. حتی اگه دو رویداد برای دکمه تعریف ایجاد کرده باشم و در یکیش کد نویسی زیادی هم انجام داده باشم باز نمی تونم اون یکی رویداد خالی رو حذف کنم

2- این کدها رو نگاه کنید

C#:
 private void Form1_Load(object sender, EventArgs e)
 
 private void Form1_KeyDown(object sender, KeyEventArgs e)


EventArgs و KeyEventArgs هر دو کلاس هستن که حدودا می دونم یکی برای رویدادهای موس و یکی برای رویدادهای صفحه کلیده. این sender و e اینجا چی هستن و کاربردشون چیه و چه کاری انجام میدن؟

3- در if (e.Control) الان اینجا باید چی بگیم مثلا e یک متغیره و Control یک خصوصیته. همچنین توی e.KeyValue و e.KeyData


4- در این کد:

C#:
if (e.KeyData == (Keys.Control | Keys.ControlKey))

چرا باید هم Keys.Control بیاد و هم Keys.ControlKey
 

the_king

مدیرکل انجمن
سلام استاد علی

1- من روی فرم یک Button ایجاد می کنم و بعد روی Button دوبار کلیک می کنم و رویداد button1_Click به صورت کامل ایجاد می شه. بعد من میگم اشتباه کردم می خوام یک رویداد دیگه ایجادکنم این رویداد رو به طور کامل انتخاب می کنم و حذف می کنم. بعد که میرم روی فرم می بینم فرم خراب شده. دوباره که میام undo می کنم و اون رویداد ایجاد می شه فرم درست می شه. خوب من نمی خوام رویدادی که برای اون دکمه ایجاد کردم دیگه اونجا باشه و می خوام یک رویداد جدید بذارم و می خوام اون کد رویداد اشتباهی رو حذف کنم اما نمی شه. راهش اینه اول Button حذف کنم و بعدا رویدادش رو حذف کنم اینجوری فرم خراب نمی شه. علتش چیه Visual Studio نمیذاره. حتی اگه دو رویداد برای دکمه تعریف ایجاد کرده باشم و در یکیش کد نویسی زیادی هم انجام داده باشم باز نمی تونم اون یکی رویداد خالی رو حذف کنم
این مشکل صرفا بخاطر یک عادت اشتباه از جانب شما پیش میاد.
ویژوال استدیو یک Designer داره که بصورت خودکار یکسری کد رو برای شما در دو فایل Form1.cs و Form1.Designer.cs می نویسه که معمولا شما فقط Form1.cs رو می بینید، چون بخش Form1.Designer.cs رو Designer اداره می کنه و در حالت عادی پنهان ئه. مادامی که شما با روال اون Designer پیش بروید، هیچ مشکلی پیش نمیاد، اما وقتی کاری رو بدون هماهنگی Designer انجام بدهید بین کدی که Designer نوشته و کدی که شما نوشته اید تناقضی ایجاد میشه که در نتیجه کد Designer به مشکل بر میخوره و کد فرم به خطا بر میخوره.
شما همیشه می توانید کد Form1.Designer.cs رو ببینید و تغییر بدهید، اما مادامی که ایرادی در کدی که Designer نوشته نباشه، بهتره اون بخش رو به Designer بسپارید و تغییرش ندهید.

وقتی شما روی Button دو بار کلیک می کنید از Designer ویژوال استدیو می خواهید که برای رخداد پیشفرض اون Button (رخداد Click) یک متد بصورت خودکار در Form1.cs بنویسه و یک کد هم بصورت خودکار در Form1.Designer.cs بنویسه تا اون متد رو به رخداد Click متصل کنه.
پس برای شما دو کد بصورت خودکار ایجاد شده، اول کد متد و دوم کدی که متد رو به رخداد متصل می کنه. شما اگر کد متد رو حذف کنید، باید کدی که متد رو به رخداد متصل می کنه هم حذف کنید، وگرنه کد دوم خطا خواهد داد.

زمانی که خواستید این متد رو از رخداد حذف کنید، باید باز از Designer بخواهید اینکار رو انجام بده، ولی چون خودتون دستی اینکار رو انجام می دهید، بخاطر عدم هماهنگی با Designer اون کدی که در Form1.Designer.cs نوشته بود همچنان سعی می کنه متدی رو به Button وصل کنه که دیگه نیست (شما متد رو حذف کرده اید) و برای همین به خطا بر میخوره.

چکار باید کرد؟ باید موقعی که میخواهید ارتباط بین رخداد Click اون دکمه و متد فلان رو حذف کنید، در فرم یکبار روی اون Button کلیک کنید تا انتخاب بشه، در پنجره Properties بخش Events رو فعال کنید و روی رخداد Click در لیست رخداد ها راست کلیک کنید و Reset رو انتخاب کنید (یا متن button1_Click مقدارش رو پاک کنید).
اگر اینکار رو بکنید اون متد دیگه نقشی در رخداد Click اون Button نداره چون کد دوم حذف شده، اگر متد کدی نداشته باشه بصورت خودکار متد هم حذف میشه ولی اگر پاک نشد بعدش خودتون هم می توانید متد رو در کد حذف کنید و دیگه خطایی نخواهد داد چون دیگه ارتباطی با Click نداره و یک متد بلا استفاده است.
رجوع شود به :
How to handle a control event (Windows Forms .NET)
2- این کدها رو نگاه کنید

C#:
 private void Form1_Load(object sender, EventArgs e)
 
 private void Form1_KeyDown(object sender, KeyEventArgs e)


EventArgs و KeyEventArgs هر دو کلاس هستن که حدودا می دونم یکی برای رویدادهای موس و یکی برای رویدادهای صفحه کلیده. این sender و e اینجا چی هستن و کاربردشون چیه و چه کاری انجام میدن؟
sender منبعی است که رخداد رو ایجاد کرده، فرضا شما دو تا دکمه button1 و button2 دارید که در Form1 قرار داره و رخداد Click هر دو شون رو هم اشتراکی به یک متد buttons_Click متصل می کنید. حالا buttons_Click از کجا میتونه بفهمه که کلیک روی button1 بوده یا button2؟ از روی مقدار sender. وقتی روی اون دکمه ها Click میشه، متد buttons_Click فراخوانی خواهد شد و sender هم شیء دکمه ای خواهد بود که رویش کلیک شده، یعنی اگر روی button1 کلیک کنید sender همون شیء button1 ئه و اگر روی button2 کلیک کنید sender اون شیء button2 میشه.
e مقداری است که داده های رخداد رو نگه میداره، فرضا در رخداد KeyDown داده ها کلید هایی که فشرده شده اند رو به متد اعلام می کنند، هر رخدادی داده ها و نقش متفاوتی داره که خاص اون رخداد ئه.
3- در if (e.Control) الان اینجا باید چی بگیم مثلا e یک متغیره و Control یک خصوصیته. همچنین توی e.KeyValue و e.KeyData
e یک پارامتر ئه (پارامتر ورودی متد Form1_KeyDown یا رخداد KeyDown) و KeyData و KeyValue مشخصه های اون کلاس KeyEventArgs هستند.
4- در این کد:

C#:
if (e.KeyData == (Keys.Control | Keys.ControlKey))

چرا باید هم Keys.Control بیاد و هم Keys.ControlKey
چون اون کلید از نوع Modifiers ئه، یک کلید معمولی نیست، از اون کلید هایی است که همراه سایر کلید ها فشرده میشه و دو تا کد داره، یکی کد خود کلید ئه و یکی کد Modifier اش که وقتی همراه سایر کلید ها فشرده شد متوجه بشوید.
هر کلیدی رو که در این لحظه فشار می دهید یا رها می کنید یک کدی داره، فرضا Keys.ControlKey، که کاری به کلید هایی که از قبل فشرده شده بودند نداره و میتونه بگه الان این رخداد به این دلیل رخ داده که کلید x رو فشار داده ایم یا کلید x رو رها کرده ایم، حالا ممکنه همراهش کلید های دیگری هم فشرده شده باشند اما اونها از قبل فشرده شده بودند و بروز رخداد بخاطر اونها نیست.

اما چند تا کلید خاص داریم (Shift و Ctrl و Alt) که می توانند همراه سایر کلید ها فشرده شوند و بهشون Modifier Keys میگن و اگر همراه کلید های دیگری فشرده بشوند، با اون کد Modifier مخصوص شون (فرضا Keys.Control) به مقدار KeyData اضافه می شوند. برای همین KeyData الزاما فقط کد یک کلید رو نداره، همراهش مقادیر Modifiers هم هست.
مثلا اگر کلید Ctrl رو پایین نگه دارید و بعدا کلید A رو فشار بدهید، همراه کد کلید A اون کد Modifier کلید Ctrl هم هست. و چون خود کلید های Modifiers هم کد عادی کلید دارند و هم کد Modifer، وقتی یکی شون رو به تنهایی فشار بدهید دو تا کد در KeyData بصورت ترکیبی دریافت می کنید، یکی کد کلید ئه (Keys.ControlKey) و دیگری کد Modifier اش (اون Keys.Control)
 

SU-57

Active Member
سلام استاد علی

1- فهمیدم که کلیدهای modifier دو تا کد دارن ولی من مثلا می خوام فقط از کد خود کلید استفاده کنم که وقتی فقط کلید control رو فشار دادم پیام بده و بنابراین این کد رو می نویسم

C#:
if (e.KeyData == Keys.ControlKey)
{
    MessageBox.Show("ctrl");
}

می بینم جواب نمیده و کلا تکی جواب نمیده و باید هر دو تا کد کلید رو با هم بیارم.

2- گفتید که KeyData از مشخصه های کلاس KeyEventArgs ئه. می شه بفرمایید انگلیسی این واژه مشخصه در زبان سی شارپ چیه

3- آقا سجاد در آموزش ویدئویی گفت که e و sender متغیر رویدادی هستند اما شما می فرمایید sender یک شی ئه. فرمودید sender شی دکمه ایه که روی آن کلیک شده. آیا یک شی می تونه متغیر باشه یا برعکس

4- آیا نیازه من یک فایل dll رو که قبلا درست کردم و در پوشه دیگه ای هست داخل پوشه پروژه جدیدم بذارم بعد رفرنسش رو اضافه کنم یا اینکه می تونم توی هاردم در یک درایو دیگه یکسری dll داشته باشم و بعد هر کدوم رو خواستم به پروژه اضافه کنم. در این صورت موقع کامپایل یا موقع ایجاد فایل نصبی با نرم افزارهای مربوطه به اون فایل dll نیاز دارم یا خودش اتوماتیک کلاس و متدهای داخلش رو به پروژه و فایل نصبی اضافه می کنه.

5- مسیر پروژه های سی شارپ که به صورت زیره می شه تغییر داد؟ اگه می شه تغییر داد همین مسیر خوبه یا بهتره مسیر دیگه ای بهش بدیم. منظورم اینه وقتی می خواهیم یک پروژه جدید ایجاد کنیم در قسمت location همیشه اتوماتیک مسیری که ما تعیین کردیم بیاد نه اینکه هر دفعه دستی مسیرو مشخص کنیم

C:\Users\Username\source\repos
 

the_king

مدیرکل انجمن
سلام استاد علی

1- فهمیدم که کلیدهای modifier دو تا کد دارن ولی من مثلا می خوام فقط از کد خود کلید استفاده کنم که وقتی فقط کلید control رو فشار دادم پیام بده و بنابراین این کد رو می نویسم

C#:
if (e.KeyData == Keys.ControlKey)
{
    MessageBox.Show("ctrl");
}

می بینم جواب نمیده و کلا تکی جواب نمیده و باید هر دو تا کد کلید رو با هم بیارم.
شرط if تون رو ببینید، نوشتید فقط زمانی که Ctrl فشار داده شده (کد کلید ContrlKey) ولی Ctrl فشرده نیست (چون کد Modifier ئه Control نداره).
همچین حالتی نمیتونه پیش بیاد، چطور ممکنه کلید Ctrl فشار داده بشه اما فشرده نشده باشه؟ به محض اینکه Ctrl رو فشار بدهید تا زمانی که از حالت فشرده در نیاد Modifier اش اعمال میشه).
2- گفتید که KeyData از مشخصه های کلاس KeyEventArgs ئه. می شه بفرمایید انگلیسی این واژه مشخصه در زبان سی شارپ چیه
Property
Properties (C# Programming Guide)
3- آقا سجاد در آموزش ویدئویی گفت که e و sender متغیر رویدادی هستند اما شما می فرمایید sender یک شی ئه. فرمودید sender شی دکمه ایه که روی آن کلیک شده. آیا یک شی می تونه متغیر باشه یا برعکس
خودش نه، مقدارش شیء ئه.
شیء نمیتونه متغیر باشه، یا متغیر نمیتونه شیء باشه. شیء یک مقدار ئه که میتونه در متغیر قرار بگیره. شیء و متغیر دو مفهوم متفاوت هستند.
شیء فلان ممکنه مقدار پارامتر یا هر نوع دیگری از متغیر باشه، نه خودش.
این کد رو ببینید :
C#:
            int a = 1;
            object b = new int[] { 1, 2, 3 };
            object c = b;
            object d = new int[] { 1, 2, 3 };
            object e = null;
a یک متغیر ئه، داخلش هم یک شیء با مقدار 1 ئه.
b و c متغیر هستند و مقدار هر دو شون هم یک شیء ئه که یک آرایه است، هر دو شون اشتراکی یک مقدار برابر دارند، دو تا شیء متفاوت داخلشون نیست، دقیقا همون شیء ای که در b هست در c هم هست، یک کپی ازش نیست، خودش ئه. انگار که یک خیابان دو تا اسم جدید و قدیم داشته باشه، دو تا اسم ئه ولی خیابون ئه یکی بیشتر نیست.
d متغیر ئه و یک شیء آرایه داخلش قرار داره که مقدارش شبیه مقدار b و c است ولی فقط مقدارش شبیه ئه، شیء متفاوتی است، با مقدار b و c برابر نیست.
e متغیر ئه، ولی مقداری نداره، خالی ئه، شیء ای داخلش نیست.

e و sender پارامتر هستند (نوعی از متغیر یا Variable)، متغیر انواع مختلفی داره که گروهی از اونها پارامتر ئه.

4- آیا نیازه من یک فایل dll رو که قبلا درست کردم و در پوشه دیگه ای هست داخل پوشه پروژه جدیدم بذارم بعد رفرنسش رو اضافه کنم یا اینکه می تونم توی هاردم در یک درایو دیگه یکسری dll داشته باشم و بعد هر کدوم رو خواستم به پروژه اضافه کنم. در این صورت موقع کامپایل یا موقع ایجاد فایل نصبی با نرم افزارهای مربوطه به اون فایل dll نیاز دارم یا خودش اتوماتیک کلاس و متدهای داخلش رو به پروژه و فایل نصبی اضافه می کنه.
هم می توانید به اون dll ئه در درایو دیگه رفرنس بدهید و هم می توانید بجای dll اش به پروژه اون dll ئه که در جای دیگری ذخیره شده رفرنس بدهید، یعنی Solution تون فقط یک پروژه نباشه، شامل دو پروژه باشه که یکی اش خروجی اش اون dll ئه.
5- مسیر پروژه های سی شارپ که به صورت زیره می شه تغییر داد؟ اگه می شه تغییر داد همین مسیر خوبه یا بهتره مسیر دیگه ای بهش بدیم. منظورم اینه وقتی می خواهیم یک پروژه جدید ایجاد کنیم در قسمت location همیشه اتوماتیک مسیری که ما تعیین کردیم بیاد نه اینکه هر دفعه دستی مسیرو مشخص کنیم

C:\Users\Username\source\repos
صد البته، خودتون انتخاب می کنید که کجا پروژه ساخته بشه و بعدا هم می توانید جابجا اش کنید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام استاد علی

3- آقا سجاد در آموزش ویدئویی گفت که e و sender متغیر رویدادی هستند اما شما می فرمایید sender یک شی ئه. فرمودید sender شی دکمه ایه که روی آن کلیک شده. آیا یک شی می تونه متغیر باشه یا برعکس

سلام
جواب کامل را که استاد دادن .

درباره ی آموزش هم چند نکته را باید بگم که بعضی هاشون را قبلا گفتم و میدونید .

- اول اینکه توی این آموزش سی شارپ (که من اون زمان فقط یکسال و خردی بود با سی شارپ کار کرده بودم) ، اشتباه هم وجود داره . (کما اینکه من توی آموزشِ حتی استادهای دانشگاه که ده ها سال ادعا میکردن آموزش میدادن ، نقص علمی دیدم) . اما سعی کردم که این اشتباه ها خیلی کم بشه که به لطف خدا ، به نظرم تا حد خوب و قبولی حس میکنم این طور بوده .

همینجا تشکر ویژه از استاد میکنم که اگه کمک های بسیار زیادشون نبودن ، نه تنها اون آموزش ، بلکه خیلی از کارهای برنامه نویسی دیگه ام ، با مشکلات زیادی مواجه میشد .


- بعضی از اشتباهاتی که در طول آموزش متوجه شدم ، در قسمت های بعد ، تصحیح شد . فرضا قسمت 11 اشکالاتی داشت که در 2 قسمت از سری 40 حدودا اصلاح شد و ... .


- یه سری نکات هست که نمیشه همه را گفت . یعنی فرضا من نکات شی گرایی را نمیتونم بیام اول (در قسمت های مربوط به procedural) بگم . بنابراین مشخص هست که تا اون قسمت ها نرسیده ، مجبورا سر بسته نکاتی را میشه گفت که همه ی ابعادِ مطالب را پوشش نده یا برای سادگی ، مختصرا کمتر از مطلب اصلی گفته بشه .


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

به این قضیه ، در ادبیات فارسی ، مَجاز گفته میشه :


و


همه دیده پر آب و دل پر ز خون
نشسته به تیمار مرگ اندرون

در این بیت "آب" ، مجاز است از اشک.
----
اینجا که میگین که گفتم e و sender یک متغییر رویدادی هست که درسته .
اما اگه جایی هم گفته باشم که اینها شی هستن ، منظورم در واقع محتوا و مقدار اون که یک شی هست ، هست. نه اینکه این باشه که sender یک متغییر نباشه .

این چیزی که استاد توضیح دادن را بصورت مبسوط در بخشی از یکی از قسمت ها توضیح دادم .
حتی قضیه ی این مَجاز در ادبیات فارسی هم فکر کنم گفته بودم .
 
آخرین ویرایش:

SU-57

Active Member
سلام
جواب کامل را که استاد دادن .

درباره ی آموزش هم چند نکته را باید بگم که بعضی هاشون را قبلا گفتم و میدونید .

- اول اینکه توی این آموزش سی شارپ (که من اون زمان فقط یکسال و خردی بود با سی شارپ کار کرده بودم) ، اشتباه هم وجود داره . (کما اینکه من توی آموزشِ حتی استادهای دانشگاه که ده ها سال ادعا میکردن آموزش میدادن ، نقص علمی دیدم) . اما سعی کردم که این اشتباه ها خیلی کم بشه که به لطف خدا ، به نظرم تا حد خوب و قبولی حس میکنم این طور بوده .

همینجا تشکر ویژه از استاد میکنم که اگه کمک های بسیار زیادشون نبودن ، نه تنها اون آموزش ، بلکه خیلی از کارهای برنامه نویسی دیگه ام ، با مشکلات زیادی مواجه میشد .


- بعضی از اشتباهاتی که در طول آموزش متوجه شدم ، در قسمت های بعد ، تصحیح شد . فرضا قسمت 11 اشکالاتی داشت که در 2 قسمت از سری 40 حدودا اصلاح شد و ... .


- یه سری نکات هست که نمیشه همه را گفت . یعنی فرضا من نکات شی گرایی را نمیتونم بیام اول (در قسمت های مربوط به procedural) بگم . بنابراین مشخص هست که تا اون قسمت ها نرسیده ، مجبورا سر بسته نکاتی را میشه گفت که همه ی ابعادِ مطالب را پوشش نده یا برای سادگی ، مختصرا کمتر از مطلب اصلی گفته بشه .


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

به این قضیه ، در ادبیات فارسی ، مَجاز گفته میشه :


و


همه دیده پر آب و دل پر ز خون
نشسته به تیمار مرگ اندرون

در این بیت "آب" ، مجاز است از اشک.
----
اینجا که میگین که گفتم e و sender یک متغییر رویدادی هست که درسته .
اما اگه جایی هم گفته باشم که اینها شی هستن ، منظورم در واقع محتوا و مقدار اون که یک شی هست ، هست. نه اینکه این باشه که sender یک متغییر نباشه .

این چیزی که استاد توضیح دادن را بصورت مبسوط در بخشی از یکی از قسمت ها توضیح دادم .
حتی قضیه ی این مَجاز در ادبیات فارسی هم فکر کنم گفته بودم .
چون اینجا جاش نیست مفصل در پیام خصوصی پاسخت رو ارسال می کنم.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد استاد
خیلی ممنون (از جواب پست 1710 و بقیه ی پست هاتون) .

استاد ، میشه یه کلاسی داشته باشیم که هم از کلاسِ ObservableCollection<T> ارث بری کنه (که تا اینجا مشکلی نیست و به راحتی میشه از این کلاس ارث بری کرد) و هم فرضا قابلیت های کلاسِ Dictionary<TKey,TValue> را داشته باشه؟

اگه آره ، به این روش میشه که باید اینترفیس هایی که کلاسِ Dictionary<TKey,TValue> پیاده سازی کرد را در کلاس خودمون اعضاشون را پیاده سازی کنیم؟
چون این جوری خیلی طول میکشه .

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

توضیحات بیشتر اینکه کلاسی بنام VssBackup دارم که اطلاعاتِ یک دونه بکاپ مثل شناسه ی بکاپ مورد نظر ، زمان تهیه ی اون بکاپ و ... را در خودش ذخیره میکنه .

یه کلاس دیگه بنام DriveVssBackupCollection دارم که از نوعِ ObservableCollection<VssBackup> ارث بری میکنه .
این کلاس ، اطلاعات مجموعه ی بکاپ های مربوط به یک درایو را در خودش ذخیره میکنه (علاوه بر اون ، اطلاعات دیگه ای مثل شناسه ی اون درایو و اطلاعات مربوط به درایو هم در خودش ذخیره میکنه) .
بنابراین این کلاسِ DriveVssBackupCollection ، مجموعه ای از (چندین) شیِ VssBackup را در خودش ذخیره میکنه (توسط ایندکسر) .


کلاسِ DriveVssBackupCollection را از ObservableCollection<T> ارث بری کردم چون امکان Binding کردن به View ، بسیار زیاد هست تا بعدا ، زمانی که اعضای کالکشن ، تغییرِ مقدار بدن ، مشکلی برای مطلع شدنِ Binding ها پیش نیاد .

حالا خواستم هم علاوه بر این ، کلاسِ DriveVssBackupCollection ، از قابلیت های Dictionary<TKey,TValue> هم استفاده کنه تا فرضا هر شیِ VssBackup ای را که در کالکشنِ DriveVssBackupCollection ذخیره میکنم ، به همراهِ شناسه ی اون بکاپ ذخیره کنم تا موقع فراخونی ، سریعتر این کار را انجام بدم و نیاز به جستجو نباشه .

به نظرتون نمیارزه برای این کار وقت بذارم (و صرفا یه متد جستجو برای این کار) در DriveVssBackupCollection بنویسم؟
تشکر
 

the_king

مدیرکل انجمن
سلامی مجدد استاد
خیلی ممنون (از جواب پست 1710 و بقیه ی پست هاتون) .

استاد ، میشه یه کلاسی داشته باشیم که هم از کلاسِ ObservableCollection<T> ارث بری کنه (که تا اینجا مشکلی نیست و به راحتی میشه از این کلاس ارث بری کرد) و هم فرضا قابلیت های کلاسِ Dictionary<TKey,TValue> را داشته باشه؟
وراثت چندگانه (Multiple inheritance) که در برخی زبان ها مثل ++C هست در #C نیست، در #C وراثت یگانه (single inheritance) است.
برای همین یک کلاس میتونه صرفا وارث یک کلاس باشه و البته میتونه صد ها اینترفیس رو همزمان پیاده سازی کنه.
توضیحات بیشتر اینکه کلاسی بنام VssBackup دارم که اطلاعاتِ یک دونه بکاپ مثل شناسه ی بکاپ مورد نظر ، زمان تهیه ی اون بکاپ و ... را در خودش ذخیره میکنه .

یه کلاس دیگه بنام DriveVssBackupCollection دارم که از نوعِ ObservableCollection<VssBackup> ارث بری میکنه .
این کلاس ، اطلاعات مجموعه ی بکاپ های مربوط به یک درایو را در خودش ذخیره میکنه (علاوه بر اون ، اطلاعات دیگه ای مثل شناسه ی اون درایو و اطلاعات مربوط به درایو هم در خودش ذخیره میکنه) .
بنابراین این کلاسِ DriveVssBackupCollection ، مجموعه ای از (چندین) شیِ VssBackup را در خودش ذخیره میکنه (توسط ایندکسر) .


کلاسِ DriveVssBackupCollection را از ObservableCollection<T> ارث بری کردم چون امکان Binding کردن به View ، بسیار زیاد هست تا بعدا ، زمانی که اعضای کالکشن ، تغییرِ مقدار بدن ، مشکلی برای مطلع شدنِ Binding ها پیش نیاد .

حالا خواستم هم علاوه بر این ، کلاسِ DriveVssBackupCollection ، از قابلیت های Dictionary<TKey,TValue> هم استفاده کنه تا فرضا هر شیِ VssBackup ای را که در کالکشنِ DriveVssBackupCollection ذخیره میکنم ، به همراهِ شناسه ی اون بکاپ ذخیره کنم تا موقع فراخونی ، سریعتر این کار را انجام بدم و نیاز به جستجو نباشه .

به نظرتون نمیارزه برای این کار وقت بذارم (و صرفا یه متد جستجو برای این کار) در DriveVssBackupCollection بنویسم؟
تشکر
ماهیت Dictionary با ObservableCollection یک تفاوت اساسی داره، در موقعیت و امکان جابجایی موقعیت آیتم ها در مجموعه که ارتباطی با مقدار شناسه شون هم نداره. ساختار Dictionary طوری نیست که به موقعیت اشیاء در مجموعه اهمیتی بده.
شما می توانید از یک شی Dictionary مستقل داخل کلاس تون برای دسترسی سریع به اشیاء مجموعه و یا بررسی وجود یک شناسه استفاده کنید.
 

SajjadKhati

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

C#:
            ((string style, int? width) view, (bool? isRunInStartup,
                List<(string driveName, bool? autoBackuping, int? autoBackupingValue)> drivesBackupings) model) settingTuples;

            settingTuples = ((style: null, width: null), (isRunInStartup: null, drivesBackupings: null));

            settingTuples.model.isRunInStartup = false;
            settingTuples.model.drivesBackupings = new List<(string driveName, bool? autoBackuping, int? autoBackupingValue)>();
            settingTuples.model.drivesBackupings[0] = ("D", false, null);

            System.Diagnostics.Debug.WriteLine(settingTuples.model.drivesBackupings[0]);
            settingTuples.model.drivesBackupings[0].autoBackuping = true;
            System.Diagnostics.Debug.WriteLine(settingTuples.model.drivesBackupings[0]);

(در خطِ یکی مونده به آخری) ، ارور زیر را میده؟ :

کد:
Cannot modify the return value of 'List<(string driveName, bool? autoBackuping, int? autoBackupingValue)>.this[int]' because it is not a variable

اما اگه همین شیِ List را در خارج از tuple (ئه بالا) بنویسم و اعضای ایندکسرش را بخوام تغییر بدم ، مشکلی نمیگیره.

توی همین tuple هم اگه بجای List ، یه آرایه ی معمولی بگیرم ، مشکلی نداره .
یعنی در کد زیر ، به درستی میشه عضوِ اعضای آرایه را تغییر داد و مشکلی نداره :

کد:
            ((string style, int? width, int? height)view, (bool? isRunInStartup, bool? isEnableSilentMode,
            (string driveName, bool? autoBackuping, int? autoBackupingValue)[] drivesBackupings, bool? isDisabledWindowsUpdate)model) settingTuples;

            settingTuples = ((style: null, width: null, height: null),
                (isRunInStartup: null, isEnableSilentMode: null, drivesBackupings: null, isDisabledWindowsUpdate: null));

            settingTuples.model.isRunInStartup = false;
            settingTuples.model.drivesBackupings = new (string driveName, bool? autoBackuping, int? autoBackupingValue)[5];
            settingTuples.model.drivesBackupings[0] = ("D", false, null);

            System.Diagnostics.Debug.WriteLine(settingTuples.model.drivesBackupings[0]);
            settingTuples.model.drivesBackupings[0].autoBackuping = true;
            settingTuples.model.drivesBackupings[0].autoBackupingValue = 1002;
            System.Diagnostics.Debug.WriteLine(settingTuples.model.drivesBackupings[0]);

تشکر استاد .
 

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد .
استاد ، چرا در tuple ئه زیر ، وقتی نوع List را میگیرم و میخوام به اعضای ایندکسرش ، مقدار بدم :

C#:
            ((string style, int? width) view, (bool? isRunInStartup,
                List<(string driveName, bool? autoBackuping, int? autoBackupingValue)> drivesBackupings) model) settingTuples;

            settingTuples = ((style: null, width: null), (isRunInStartup: null, drivesBackupings: null));

            settingTuples.model.isRunInStartup = false;
            settingTuples.model.drivesBackupings = new List<(string driveName, bool? autoBackuping, int? autoBackupingValue)>();
            settingTuples.model.drivesBackupings[0] = ("D", false, null);

            System.Diagnostics.Debug.WriteLine(settingTuples.model.drivesBackupings[0]);
            settingTuples.model.drivesBackupings[0].autoBackuping = true;
            System.Diagnostics.Debug.WriteLine(settingTuples.model.drivesBackupings[0]);

(در خطِ یکی مونده به آخری) ، ارور زیر را میده؟ :

کد:
Cannot modify the return value of 'List<(string driveName, bool? autoBackuping, int? autoBackupingValue)>.this[int]' because it is not a variable

اما اگه همین شیِ List را در خارج از tuple (ئه بالا) بنویسم و اعضای ایندکسرش را بخوام تغییر بدم ، مشکلی نمیگیره.

توی همین tuple هم اگه بجای List ، یه آرایه ی معمولی بگیرم ، مشکلی نداره .
یعنی در کد زیر ، به درستی میشه عضوِ اعضای آرایه را تغییر داد و مشکلی نداره :

کد:
            ((string style, int? width, int? height)view, (bool? isRunInStartup, bool? isEnableSilentMode,
            (string driveName, bool? autoBackuping, int? autoBackupingValue)[] drivesBackupings, bool? isDisabledWindowsUpdate)model) settingTuples;

            settingTuples = ((style: null, width: null, height: null),
                (isRunInStartup: null, isEnableSilentMode: null, drivesBackupings: null, isDisabledWindowsUpdate: null));

            settingTuples.model.isRunInStartup = false;
            settingTuples.model.drivesBackupings = new (string driveName, bool? autoBackuping, int? autoBackupingValue)[5];
            settingTuples.model.drivesBackupings[0] = ("D", false, null);

            System.Diagnostics.Debug.WriteLine(settingTuples.model.drivesBackupings[0]);
            settingTuples.model.drivesBackupings[0].autoBackuping = true;
            settingTuples.model.drivesBackupings[0].autoBackupingValue = 1002;
            System.Diagnostics.Debug.WriteLine(settingTuples.model.drivesBackupings[0]);

تشکر استاد .
چون value type ئه.
چون مشخصه یا indexer یا متد ای که مقدار value type ای مثل struct و tuple رو بر می گردونه داره یک کپی از مقدار رو بر میگردونه، ارجاع به مقدار اصلی نیست. برای همین نمی توانید فیلدی رو در مقدار برگشتی تغییر بدهید.
صورت مساله رو ساده می کنم. شما یک struct ساده مثل A رو در نظر بگیرید :
C#:
        struct A
        {
            public object Value;
        }
می توانید مقدار Value رو (نوع داده Value مهم نیست) در A ای که یک value type ئه اینطوری تغییر بدهید؟
C#:
            var a = new List<A>();
            a.Add(new A());
            a[0].Value = null;
نمی توانید. مشکل چیه؟ اون indexer در List به شما یک value type تحویل داده از نوع A که کپی مقدار اولین عضو لیست ئه.
و indexer اصلا متوجه نخواهد شد که شما با فیلد Value در اون داده کپی شده چه می کنید. شما هر بلایی سر اون داده کپی شده بیاورید تاثیری روی a[0] نمیذاره چون ارجاع به مقدار نیست، یک کپی از داده است. می خواهید Value چیزی رو تغییر بدهید که ربطی به اون عضو در لیست نداره.
برای همین کامپایلر جلوی انجام این عمل بی فایده رو میگیره.
 

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

بالا