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

SU-57

Active Member
آقا سجاد اونی که شما گفتی برای من درست کار می کنه یعنی هر دو عدد 10 رو نشون میده (قسمت 7 ، 1:50:00 چند دقیقه عقب تر)

کد:
int myint_1 = 10;
myint_1 = myint_1++;
MessageBox.Show(myint_1.ToString());


کد:
int myint_1 = 10;
int myint_2 = myint_1++;
MessageBox.Show(myint_2.ToString());
 
آخرین ویرایش:

the_king

مدیرکل انجمن
ممنون
نه
همون ارور هه
Use of unassigned local variable 'b'
اون x و y رو کامنت کردم . یعنی حذف شدن و وجود ندارن
عکس رو پیوست کردم

مشاهده پیوست 111958
اونا رو که میدونم، کاری به اونا ندارم، به btn_ و StrBld کار داره، میگه چرا از پروپرتی Btn استفاده کردید پیش از آنکه به btn_ و StrBld صریحا مقداری تخصیص بدهید. کل struct رو یک مجموعه کلی در نظر میگیره، وقتی یه فیلدشم مقدار نداشته باشه کل struct رو uninitialized میدونه.
 

SajjadKhati

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

the_king

مدیرکل انجمن
ممنون
استاد علی ، میگم تفاوت رویدادهای کیبرد KeyDown و KeyPress چی هه؟ یکی میگفت تفاوت شون توی میزان اجراست . میگفت KeyPress (احتمالا)، تا زمانی که دکمه فشار داده بشه ، کدش اجرا میشه و به درد طراحی بازی میخوره ولی توی اون رویداد دیگه ، کد فقط یکبار اجرا میشه
اما من که تست کردم ، در هر دو رویداد ، بصورت مداوم کد اجرا میشه (فقط یکبار نیست)
البته نوع متغییر رویدادیشون که با هم متفاوت هست ، به کنار
کلا هیچکدوم از اینها برای بازی مناسب نیستند. KeyDown خودش نتیجه چند مرحله نظارت و فیلتر شدن کلید ها است. متد ProcessCmdKey رو override کنید که چند مرحله قبل تر از KeyDown رخ میده.
KeyDown و KeyUp رخداد های کلید فیزیکی هستند، برای همین واسه فشار دادن تنهایی کلیدی مثل Alt و Ctrl هم رخ می دهند. اما KeyPress بعد از KeyDown و صرفا برای کلید هایی است که پردازش شده اند و در نتیجه پردازش یک کاراکتر تولید می کنند. مثلا فشار دادن Ctrl و Delete و Caps Lock کاراکتر تولید نمی کنه که بخاطرش KeyPress رخ بده. خاصیت KeyPress به اینه که وضعیت صفحه کلید رو در نظر میگیره و پردازش زبان رو انجام میده، مثلا وقتی A رو فشار بدهید با توجه به وضعیت Shift و Caps Lock و زبان کاراکتر مناسب a یا A یا حتی ش رو تولید می کنه، در حالی که برای KeyDown اصلا مهم نیست که Caps Lock در چه وضعیتیه و صفحه کلید روی زبان فارسیه یا انگلیسیه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
کلا هیچکدوم از اینها برای بازی مناسب نیستند. KeyDown خودش نتیجه چند مرحله نظارت و فیلتر شدن کلید ها است. متد ProcessCmdKey رو override کنید که چند مرحله قبل تر از KeyDown رخ میده.
KeyDown و KeyUp رخداد های کلید فیزیکی هستند، برای همین واسه فشار دادن تنهایی کلیدی مثل Alt و Ctrl هم رخ می دهند. اما KeyPress بعد از KeyDown و صرفا برای کلید هایی است که پردازش شده اند و در نتیجه پردازش یک کاراکتر تولید می کنند. مثلا فشار دادن Ctrl و Delete و Caps Lock کاراکتر تولید نمی کنه که بخاطرش KeyPress رخ بده. خاصیت KeyPress به اینه که وضعیت صفحه کلید رو در نظر میگیره و پردازش زبان رو انجام میده، مثلا وقتی A رو فشار بدهید با توجه به وضعیت Shift و Caps Lock و زبان کاراکتر مناسب a یا A یا حتی ش رو تولید می کنه، در حالی که برای KeyDown اصلا مهم نیست که Caps Lock در چه وضعیتیه و صفحه کلید روی زبان فارسیه یا انگلیسیه.

آها ممنون
پس تفاوت اش اینه که توی توی KeyPress حساس بودن به دکمه های شیفت و ... حتی فارسی و بقیه ی زبان ها هست
-----------------
یه سئوال دیگه اینکه میدونیم همه ی enum ها از کلاس System.Enum ارث میبرن و اون هم از کلاس System.ValueType و اونم از کلاس Object
ولی وقتی یه enum ای که درست میکنیم رو صریحا بگیم از کلاس short به ارث ببره ، در اون صورت خود short هم که از کلاس دیگه ای (بجز object) ارث بری نمیکنه . پس چطور با این حال ، وقتی شی ای از این نوع enum درست کنیم ، باز هم اعضای کلاس System.Enum ، لیست میشن؟
دوم اینکه چرا خودمون اگه بصورت صریح بگیم enum مون از کلاس System.Enum ارث بری کنه ، کمپایلر ارور میده؟!
 

the_king

مدیرکل انجمن
آها ممنون
پس تفاوت اش اینه که توی توی KeyPress حساس بودن به دکمه های شیفت و ... حتی فارسی و بقیه ی زبان ها هست
-----------------
یه سئوال دیگه اینکه میدونیم همه ی enum ها از کلاس System.Enum ارث میبرن و اون هم از کلاس System.ValueType و اونم از کلاس Object
ولی وقتی یه enum ای که درست میکنیم رو صریحا بگیم از کلاس short به ارث ببره ، در اون صورت خود short هم که از کلاس دیگه ای (بجز object) ارث بری نمیکنه . پس چطور با این حال ، وقتی شی ای از این نوع enum درست کنیم ، باز هم اعضای کلاس System.Enum ، لیست میشن؟
دوم اینکه چرا خودمون اگه بصورت صریح بگیم enum مون از کلاس System.Enum ارث بری کنه ، کمپایلر ارور میده؟!
اینکه جلوی enum یک نوع داده تعیین می کنید ظاهر Syntax اش شبیه به ارث بری ئه کلاسها است، ولی واقعا که ارث بری نیست که بگید چرا متد هاشو نشون نمیده، اون چیزی که مشخص می کنید underlying type ئه، یعنی نوع داده صحیح بدون اعشاری که در زیر این پوسته enum برای نگهداری مقدارش بکار میره. و طبیعتا هم در این مورد دست تون هم در انتخاب نوع داده خیلی باز نیست.

در نظر بگیرید که در #C انواع داده ای مثل short و موارد خاصی مثل enum و struct و class باید از ابتدا وجود داشته باشند تا بشه بعد کدی نوشت که شامل اینها باشند، الزاما نمیشه که خودشون از ابتدا نباشند و بعد با یک کد #C تعریف و پیاده سازی کرد. همه اینها یک ساختار درونی دارند که شاید اصلا با دستور زبان #C به تنهایی قابل تعریف نباشند. و همچنین توجه داشته باشید که هر چیزی داخل System می بینید مجزا و مستقل از زبان #C ئه. #C داره از اینها استفاده می کنه، الزاما همه بخش های System هم برای برنامه نویس سطح بالا نیست، شما که دارید در زبان #C برنامه نویسی می کنید، سطح تون بالاتر از برنامه نویسی است که در طراحی Framework یا #C نقش داره. بخش هایی از System صرفا مصرف داخلی اون برنامه نویس های سطح پایینه. این رو خیلی کلی گفتم، نه فقط مورد Enum. توقع نداشته باشید که بتوانید هر نوع کدی که با هسته Framework در ارتباطه و در ظاهر قابل اجرا است رو پیاده سازی کنید :

کد:
public abstract class Enum : ValueType, IComparable, IFormattable, IConvertible
{
}

public struct Int16 : IComparable, IFormattable, IConvertible, IComparable<short>, IEquatable<short>
{
    internal short m_value;
}
 

SajjadKhati

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

کد:
    public struct PracticeStruct
    {
        public int AutoProp { get; set; }
        private int _manulProp;
        public int ManulProp
        {
            get
            {
                return this._manulProp;
            }
            set
            {
                this._manulProp = value;
            }
        }
        public int X;
        public int Y;
        public StringBuilder StrBld;
        public static int StaticField;

        public PracticeStruct(string myStr)
        {
            this._manulProp = 80;
            this.AutoProp = 5;
            this.X = 10;
            this.Y = 20;
            this.StrBld = new StringBuilder(myStr);
        }
    }

در رویدادی در کلاس فرم1 ، وقتی شی ای از این استراکچر میسازم و nullable اش میکنم :


کد:
PracticeStruct? a = new PracticeStruct();
دیگه توسط این متغییر a ، به اعضای استراکچر PracticeStruct یعنی مثلا عضو X و Y و ManulProp و ... دسترسی ندارم و بجاش اعضایی از همین استراکچر لیست میشن که من اصلا توی این استراکچر ننوشتم یا اجدادش این عضو رو نداشتن ! مثل عضو پروپرتی ای بنام Value توسط متغییر a در دسترس قرار میگیره که اصلا توش وجود نداره !
چرا؟ و اینکه نمیشه وقتی nullable اش میکنیم ، دیگه به اعضاش دسترسی داشته باشیم؟

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

توی قضیه ی اینترفیس ها :
1) چرا اعضای اینترفیس ، فقط باید public باشن؟ مثلا اگه internal باشن ، چی میشه؟ یا هر سطح دسترسی دیگه؟ پس با اون حال ، چرا خود اینترفیس ها رو میشه internal تعریف کرد؟ وقتی سطح دسترسی خود اینترفیس ، internal باشه و سطح دسترسی اعضاش ، public باشه ، اتوماتیک سطح دسترسی اعضاش ، به internal تنزل داده میشه!

2) چرا خود ایترفیس و اعضاش ، نمیتونن static باشن؟ آیا دلیل اش مثل اعضای abstract (و virtual و override) اینه که وقتی این اعضا در کلاس نوادگان ، override میشن ، وقتی نوع داده ای متفاوت باشه و شی ای از اون عضو (فرزند یا نوادگان) ساخته شد ، همون عضو override شده ی در کلاس فرزند یا نوه رو اجرا کنه؟ چون اگه استاتیک باشه ، دیگه وابسته به شی نیست و دقیقا همون عضو در همون کلاس استاتیک (یا اجدادش) رو اجرا میکنه .
که احتمالا این طور نیست ،آخه اینترفیس ها مثل اعضای abstract و virtual ، نمیتونن در کلاس های نوادگان ، چندین بار پیاده سازی بشن تا ، وقتی که شی ای از فرزند یا نوه ساخته شد ، اون عضو override شده در همون کلاس رو فراخونی کنه . اعضای اینترفیس ، اگه بخواد در کلاس نوه ، دوباره پیاده سازی بشه ، hide میشه

3) در مثال صفحه ی زیر :

tahlildadeh

طرف در کلاس Dog ، یکی از اینترفیس هایی که پیاده سازی کرد ، اینترفیس IComparable بود (که برای قباس دو شی بکار میره) . تا اینجا مشکلی نیست . ولی وقتی در متد Main ، نوشت :

کد:
            List<dog> dogs = new List<dog>();
            dogs.Add(new Dog("Fido"));
            dogs.Add(new Dog("Bob"));
            dogs.Add(new Dog("Adam"));
خوب ، این متغییر dogs ، شی ای از کلاس List هه . پس وقتی بعدش مینویسه dogs.Sort(); ، باید متد Sort ای که در کلاس List پیاده سازی شده رو اجرا کنه . از اون طرف هم کلاس Dog و List ، رابطه ی ارث بری هم با هم ندارن پس در کد بالا ، کلاس Dog چه از اینترفیس IComparable ارث بری کنه یا نکنه (یعنی متد CompareTo رو پیاده سازی کنه یا نکنه) ، نباید فرقی کنه چون متد Sort از کلاس List باید اجرا بشه و ربطی نباید به متد CompareTo در کلاس Dog داشته باشه . ولی این طور نیست و ربط داره . چرا ربط داره و چه ربطی داره؟ و چرا وقتی اینترفیس IComparable در کلاس Dog ، پیاده سازی نشه ، با اونکه متد Sort از کلاس List اجرا میشه ، ارور میده؟! یعنی کلا رابطه ی متد Sort در کلاس List و رابطه ی اینترفیس IComparable (متد CompareTo) در کلاس Dog ، چیه؟
 

the_king

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

میگم چرا وقتی یه استراکچر درست میکنم ؛ حالا موقع ساخت شی از اون استراکچر ، وقتی اون شی را nullable اش میکنم ، دیگه توسط اون شی ، به اعضاش دسترسی ندارم و بجاش ، یه اعضای عجیب و قریب رو توی اینتل لایسنس لیست میکنه . قضیه اش چیه؟ چرا این طوره؟
تا حالا با ? ئه کار نکرده بودید؟ همینطوریه. در اصل Nullable یک struct خیلی ساده است که دو تا مقدار داره، یکی اش مقدار اون ساختار ئه که دارید Nullable اش می کنید و دومیش هم یک bool ئه که بگه الان null هست یا نیست. جز این راه هم راه دیگه ای نبوده، چون میدونید نمیشه از struct ئه وراثت گرفت بهش یک فیلد جدید اضافه کرد، برای همین دیگه struct تون بعد Nullable شدن نمیتونه همونطور که بود باشه. محتویات struct از طریق Value در دسترس ئه، و قبلش هم باید با HasValue مطمئن بشید که متغیر تون null نیست و مقدار داره. ()GetValueOrDefault هم برای این کاربرد داره که اگه بخواهید null بودن رو چک نکنید و برای وقتی null ئه مقدار ئه پیشفرض اون ساختار رو دریافت کنید.

بعد اینکه چرا یک استراکچر ، نمیتونه استاتیک باشه؟
struct یک ساختار داده ترکیبی Value Type ئه، وقتی کاربرد داره که بشه از این ساختار داده نمونه هایی ساخت که Value Type باشند، static دقیقا مخالف نمونه ساختنه، وقتی کلاسی رو static می کنید دیگه نمیشه ازش نمونه ساخت، struct ای که بخواد static باشه کاربرد نداره، بدرد نخور میشه، مثل اینه که بگید میخوام یه نوع داده ترکیبی جدید بسازم که Value Type هم باشه ولی نمیخوام ابدا ازش استفاده بشه. خوب وقتی نمیخواهید ازش نمونه بسازید دیگه Value Type بودنش چی چیه. اگه موردی دارید که به نظرتون باید static struct باشه هیچ دلیلی برای struct بودنش نمیتونید داشته باشید، چون نمیخواستید ازش نمونه بسازید، منطقی بوده که static class باشه.
توی قضیه ی اینترفیس ها :
1) چرا اعضای اینترفیس ، فقط باید public باشن؟ مثلا اگه internal باشن ، چی میشه؟ یا هر سطح دسترسی دیگه؟ پس با اون حال ، چرا خود اینترفیس ها رو میشه internal تعریف کرد؟ وقتی سطح دسترسی خود اینترفیس ، internal باشه و سطح دسترسی اعضاش ، public باشه ، اتوماتیک سطح دسترسی اعضاش ، به internal تنزل داده میشه!

2) چرا خود ایترفیس و اعضاش ، نمیتونن static باشن؟ آیا دلیل اش مثل اعضای abstract (و virtual و override) اینه که وقتی این اعضا در کلاس نوادگان ، override میشن ، وقتی نوع داده ای متفاوت باشه و شی ای از اون عضو (فرزند یا نوادگان) ساخته شد ، همون عضو override شده ی در کلاس فرزند یا نوه رو اجرا کنه؟ چون اگه استاتیک باشه ، دیگه وابسته به شی نیست و دقیقا همون عضو در همون کلاس استاتیک (یا اجدادش) رو اجرا میکنه .
که احتمالا این طور نیست ،آخه اینترفیس ها مثل اعضای abstract و virtual ، نمیتونن در کلاس های نوادگان ، چندین بار پیاده سازی بشن تا ، وقتی که شی ای از فرزند یا نوه ساخته شد ، اون عضو override شده در همون کلاس رو فراخونی کنه . اعضای اینترفیس ، اگه بخواد در کلاس نوه ، دوباره پیاده سازی بشه ، hide میشه
خوب interface ها رو درک نکردید، interface معرفی متد ئه، پیاده سازیش نیست، این که بگید public یا internal ئه مربوط به پیاده سازیه، interface اصلا همچین مواردی که مربوط به پیاده سازی ئه رو نداره که حالا بخواد متد اش public باشه یا نباشه. public هم نیست، فقط متد رو معرفی می کنه، نوع دسترسی تعیین نمی کنه.
کد:
    public interface IFirst
    {
        void X();
    }

    public interface ISecond
    {
        void X();
    }

    public class Test : IFirst, ISecond
    {
        void IFirst.X()
        {
            MessageBox.Show("IFirst.X()");
        }

        void ISecond.X()
        {
            MessageBox.Show("ISecond.X()");
        }

        public void X()
        {
            MessageBox.Show("X()");
        }
    }
کد:
            var t = new Test();
            ((IFirst)t).X();
            ((ISecond)t).X();
            t.X();

خوب ، این متغییر dogs ، شی ای از کلاس List هه . پس وقتی بعدش مینویسه dogs.Sort(); ، باید متد Sort ای که در کلاس List پیاده سازی شده رو اجرا کنه . از اون طرف هم کلاس Dog و List ، رابطه ی ارث بری هم با هم ندارن پس در کد بالا ، کلاس Dog چه از اینترفیس IComparable ارث بری کنه یا نکنه (یعنی متد CompareTo رو پیاده سازی کنه یا نکنه) ، نباید فرقی کنه چون متد Sort از کلاس List باید اجرا بشه و ربطی نباید به متد CompareTo در کلاس Dog داشته باشه . ولی این طور نیست و ربط داره . چرا ربط داره و چه ربطی داره؟ و چرا وقتی اینترفیس IComparable در کلاس Dog ، پیاده سازی نشه ، با اونکه متد Sort از کلاس List اجرا میشه ، ارور میده؟! یعنی کلا رابطه ی متد Sort در کلاس List و رابطه ی اینترفیس IComparable (متد CompareTo) در کلاس Dog ، چیه؟
برای مرتب کردن یک مجموعه یک نیاز اساسی هست، امکان مقایسه اعضاء، یعنی دو تا عضو رو بشه با هم مقایسه کرد و معلوم بشه برابرند یا کدوم شون بزرگتر از اون یکی ئه. این یه متد لازم داره که فرضا دو تا Dog رو مقایسه کنه و یک مقدار int برگردونه که نتیجه مقایسه دو تا Dog ئه. این متد مقایسه هم به چند روش قابل پیاده سازیه، نه فقط یک روش. یک روش همونه که خود اون ساختار IComparable مناسب رو پیاده سازی کرده باشه که در این حالت Sort از همون شیوه مقایسه پیشفرض IComparable استفاده می کنه و نیازی به اطلاعات اضافی نداره. یک روش دیگه اینه که IComparer مناسبی رو بسازید و به Sort ازش شیء تحویل بدید. تفاوت اصلی در اینه که IComparer اصلا کارش مقایسه است، معمولا هم مستقل از کلاس و ساختار مورد نظر شما است، شما ممکنه برای IComparer تون مثل StringComparison چندین روش مقایسه متفاوت تعریف کنید و فرضا بتونید بگید موقع مرتب کردن Dog ها بر اساس رنگ شون مرتبشون کنه، یا سن شون، یا وزن شون یا نژاد شون. در IComparable دست تون اینطوری در شیوه مرتب سازی باز نبود.
اون Sort یک متد کلی ئه، باید آمادگی داشته باشه که با انواع کلاس ها و ساختار ها کار کنه، برای همین خودش اصلا نمیتونه درگیر نحوه مرتب سازی باشه، مقایسه کردن ها رو خودش نمی کنه. موقع مرتب سازی میاد چک می کنه IComparable مناسب پیاده سازی شده یا نه و اگه شده ازش استفاده می کنه.
 

SajjadKhati

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


تا حالا با ? ئه کار نکرده بودید؟ همینطوریه. در اصل Nullable یک struct خیلی ساده است که دو تا مقدار داره، یکی اش مقدار اون ساختار ئه که دارید Nullable اش می کنید و دومیش هم یک bool ئه که بگه الان null هست یا نیست. جز این راه هم راه دیگه ای نبوده، چون میدونید نمیشه از struct ئه وراثت گرفت بهش یک فیلد جدید اضافه کرد، برای همین دیگه struct تون بعد Nullable شدن نمیتونه همونطور که بود باشه. محتویات struct از طریق Value در دسترس ئه، و قبلش هم باید با HasValue مطمئن بشید که متغیر تون null نیست و مقدار داره. ()GetValueOrDefault هم برای این کاربرد داره که اگه بخواهید null بودن رو چک نکنید و برای وقتی null ئه مقدار ئه پیشفرض اون ساختار رو دریافت کنید.
ممنون استاد علی :rose:
نه کار نکردم . یعنی تک و توک با استراکچرهای int کار کردم ولی حواسم به این قضیه اش نبود
پس با پروپرتی Value که همون استراکچر رو برمیگردونه ، میشه به اعضاش دسترسی داشت منتها چون این پروپرتی فقط خوندنی هست ، نمیشه مقداری بهش داد . توسط یه پروپرتی هم، نمیشه اعضای یک استراکچر رو مقداردهی کرد ، بنابراین بهتره برای مقداردهی ، بهتره کاملترین متد سازنده ی اون استراکچر رو مقداردهی کنیم همون اول
با این حال ، دلیل شو دقیق متوجه نشدم
:)

struct یک ساختار داده ترکیبی Value Type ئه، وقتی کاربرد داره که بشه از این ساختار داده نمونه هایی ساخت که Value Type باشند، static دقیقا مخالف نمونه ساختنه، وقتی کلاسی رو static می کنید دیگه نمیشه ازش نمونه ساخت، struct ای که بخواد static باشه کاربرد نداره، بدرد نخور میشه، مثل اینه که بگید میخوام یه نوع داده ترکیبی جدید بسازم که Value Type هم باشه ولی نمیخوام ابدا ازش استفاده بشه. خوب وقتی نمیخواهید ازش نمونه بسازید دیگه Value Type بودنش چی چیه. اگه موردی دارید که به نظرتون باید static struct باشه هیچ دلیلی برای struct بودنش نمیتونید داشته باشید، چون نمیخواستید ازش نمونه بسازید، منطقی بوده که static class باشه.
ممنون
اینا رو میدونم
منظور دقیق ترم اینه که چرا استراکچر که value type هست ، وقتی کاربرد داره که بشه ازش شی ساخت؟
یعنی چرا کلاس که reference type هست ، فقط زمانی کاربرد نداره که بشه ازش شی ساخت؟
یعنی value type بودن ، دقیقا چرا باید ازش حتما نمونه ساخته بشه ولی برای reference type این قضیه ضرورتی نداره؟


خوب interface ها رو درک نکردید، interface معرفی متد ئه، پیاده سازیش نیست، این که بگید public یا internal ئه مربوط به پیاده سازیه، interface اصلا همچین مواردی که مربوط به پیاده سازی ئه رو نداره که حالا بخواد متد اش public باشه یا نباشه. public هم نیست، فقط متد رو معرفی می کنه، نوع دسترسی تعیین نمی کنه.
کد:
    public interface IFirst
    {
        void X();
    }

    public interface ISecond
    {
        void X();
    }

    public class Test : IFirst, ISecond
    {
        void IFirst.X()
        {
            MessageBox.Show("IFirst.X()");
        }

        void ISecond.X()
        {
            MessageBox.Show("ISecond.X()");
        }

        public void X()
        {
            MessageBox.Show("X()");
        }
    }
کد:
            var t = new Test();
            ((IFirst)t).X();
            ((ISecond)t).X();
            t.X();
اول بگم که جواب سئوال شماره ی 2 که پرسیده بودم رو ندادین (ممنون میشم اگه بدین)
--------------
من دقیق متوجه نشدم . یعنی منظورتون اینه که هر چیزی ، پیاده سازی نداشته باشه ، چیزی به عنوان سطح دسترسی (public یا internal و ...) نداره و تعریف سطح دسترسی براش بی معنی هست؟
اگه آره ، پس چرا اعضای abstract ، که مثل اینترفیس ها پیاده سازی ندارن ، سطح دسترسی قبول میکنن (حتی protected و ... رو) ؟!
رابطه ی کدی که مثال زدین به این قضیه رو دقیق متوجه نشدم
:)

برای مرتب کردن یک مجموعه یک نیاز اساسی هست، امکان مقایسه اعضاء، یعنی دو تا عضو رو بشه با هم مقایسه کرد و معلوم بشه برابرند یا کدوم شون بزرگتر از اون یکی ئه. این یه متد لازم داره که فرضا دو تا Dog رو مقایسه کنه و یک مقدار int برگردونه که نتیجه مقایسه دو تا Dog ئه. این متد مقایسه هم به چند روش قابل پیاده سازیه، نه فقط یک روش. یک روش همونه که خود اون ساختار IComparable مناسب رو پیاده سازی کرده باشه که در این حالت Sort از همون شیوه مقایسه پیشفرض IComparable استفاده می کنه و نیازی به اطلاعات اضافی نداره. یک روش دیگه اینه که IComparer مناسبی رو بسازید و به Sort ازش شیء تحویل بدید. تفاوت اصلی در اینه که IComparer اصلا کارش مقایسه است، معمولا هم مستقل از کلاس و ساختار مورد نظر شما است، شما ممکنه برای IComparer تون مثل StringComparison چندین روش مقایسه متفاوت تعریف کنید و فرضا بتونید بگید موقع مرتب کردن Dog ها بر اساس رنگ شون مرتبشون کنه، یا سن شون، یا وزن شون یا نژاد شون. در IComparable دست تون اینطوری در شیوه مرتب سازی باز نبود.
اون Sort یک متد کلی ئه، باید آمادگی داشته باشه که با انواع کلاس ها و ساختار ها کار کنه، برای همین خودش اصلا نمیتونه درگیر نحوه مرتب سازی باشه، مقایسه کردن ها رو خودش نمی کنه. موقع مرتب سازی میاد چک می کنه IComparable مناسب پیاده سازی شده یا نه و اگه شده ازش استفاده می کنه.

میدونم . سئوالم چیز دیگه ای بود
سئوالم اینه که رابطه ی متد Sort که درون کلاس List هست ، با اعضای پیاده سازی شده ی اینترفیس IComparable (یعنی متد CompareTo) در کلاس Dog چیه؟
یعنی وقتی اینترفیس IComparable در کلاس Dog پیاده سازی شد ، متد Sort چجوری میفهمه که باید متد CompareTo در کلاس Dog رو فراخونی کنه؟
نمیدونم منظورهام رو تونستم برسونم یا نه
------------------
درباره ی اینترفیس IComparer هم سئوالی داشتم و اینکه وقتی اورلود متد Sort مربوط به این اینترفیس رو مقداردهی میکنیم ، مگه نباید یک شی ای از فرزندان این اینترفیس رو بهش بدیم؟ آخه اینترفیس که شی قبول نمیکنه . پس اشکال کد زیر ، یعنی اشکال خط myVar.Sort(a); چیه؟ :

کد:
        public class Dog : IAnimal, IComparer
        {
            private string name;

            public Dog(string name)
            {
                this.Name = name;
            }

            public string Describe()
            {
                return "Hello, I'm a dog and my name is " + this.Name;
            }

            public int Compare(object x, object y)
            {
                MessageBox.Show(x.ToString() + "\n" + y.ToString());
                return 5;
            }

            public string Name
            {
                get { return name; }
                set { name = value; }
            }
        }



        interface IAnimal
        {
            string Describe();

            string Name
            {
                get;
                set;
            }
        }

حالا در رویدادی ، در فرم1 (اشکال اون خطی که گفتم در کد زیر ، چیه؟) :


کد:
        private void btnInterface1_Click(object sender, EventArgs e)
        {
            List<Page2Class.Dog> myVar = new List<Page2Class.Dog>();
            Page2Class.Dog a = new Page2Class.Dog("jorg_10");
            myVar.Add(a);
            myVar.Add(new Page2Class.Dog("jorg_2"));
            myVar.Add(new Page2Class.Dog("jorg_1"));
            myVar.Add(new Page2Class.Dog("abc"));

            myVar.Sort(a);

            foreach (Page2Class.Dog item in myVar)
            {
                MessageBox.Show(item.Name);
            }
        }

میگه نمیتونه نوع Dog رو به IComparer تبدیل کنه!
Dog که فرزند IComparer هه . نیاز به تبدیل نباید داشته باشه
و کلا اینکه کد بالا رو چجوری میشه درست کرد؟
 

the_king

مدیرکل انجمن
ممنون استاد علی :rose:
نه کار نکردم . یعنی تک و توک با استراکچرهای int کار کردم ولی حواسم به این قضیه اش نبود
پس با پروپرتی Value که همون استراکچر رو برمیگردونه ، میشه به اعضاش دسترسی داشت منتها چون این پروپرتی فقط خوندنی هست ، نمیشه مقداری بهش داد . توسط یه پروپرتی هم، نمیشه اعضای یک استراکچر رو مقداردهی کرد ، بنابراین بهتره برای مقداردهی ، بهتره کاملترین متد سازنده ی اون استراکچر رو مقداردهی کنیم همون اول
با این حال ، دلیل شو دقیق متوجه نشدم
:)
خودتونم میخواستید چیزی شبیه به Nullable بسازید همین مشکل رو پیدا می کردید که نمیتوانستید به فیلد های struct از طریق Property مقدار بدید که قبلا هم توضیح دادم چرا.

ممنون
اینا رو میدونم
منظور دقیق ترم اینه که چرا استراکچر که value type هست ، وقتی کاربرد داره که بشه ازش شی ساخت؟
یعنی چرا کلاس که reference type هست ، فقط زمانی کاربرد نداره که بشه ازش شی ساخت؟
یعنی value type بودن ، دقیقا چرا باید ازش حتما نمونه ساخته بشه ولی برای reference type این قضیه ضرورتی نداره؟
شما یک static class بسازید و یک فیلدی داخلش بسازید، این کلاس همیشه یک نمونه static ئه و مقدارش فیلد اش هم همیشه یک نمونه است، نمیشه دو تا نمونه با دو تا مقدار متفاوت برای اون فیلد وجود داشته باشه.
حالا اگه شما این نمونه رو داخل یک متغیر قرار بدید و کپی کنید در یک متغیر دیگه، چی کپی میشه؟ Reference اش. یعنی همچنان یک نمونه داریم با همون یک مقدار برای فیلد. هر تغییری در مقدار فیلد بدید در هر دو متغیر همون مقدار رو می بینید. اما اگه static struct بود چی؟ شما به محض اینکه مقدار struct رو از یک متغیر به متغیر دیگه ای کپی می کردید کل حافظه static ئه کپی میشد، یعنی دیگه یک نمونه نبود، دو تا میشد. این با اصل ذات static بودنش در تناقض ئه، اگر مقدار فیلد رو در یک متغیر عوض می کردید در دومی مقدار فیلد همچنان مقدار قبلی میبود. برای همینه که نمیشه static struct ای وجود داشته باشه، چون static بودن با Value Type بودنش جور در نمیاد.
اول بگم که جواب سئوال شماره ی 2 که پرسیده بودم رو ندادین (ممنون میشم اگه بدین)

مگه سوال در مورد static بودن interface و اعضاء اش نبود؟ گفتم که ماهیت interface رو درست درک نکردید. پیاده سازی نداره که static باشه. static interface یعنی چی؟ خودتون میتونید تعریفش کنید بگید چیه؟ مگه شما میتوانستید با new از interface شی بسازید که حالا static اش کنید تا نشه ازش شیء ساخت؟ مگه interface ها فیلدی داشتن که بهشون حافظه static اختصاص بده؟ interface که خودش پیاده سازی نداره که بخواهیم اعضاء اش رو static کنیم.

من دقیق متوجه نشدم . یعنی منظورتون اینه که هر چیزی ، پیاده سازی نداشته باشه ، چیزی به عنوان سطح دسترسی (public یا internal و ...) نداره و تعریف سطح دسترسی براش بی معنی هست؟
اگه آره ، پس چرا اعضای abstract ، که مثل اینترفیس ها پیاده سازی ندارن ، سطح دسترسی قبول میکنن (حتی protected و ... رو) ؟!
رابطه ی کدی که مثال زدین به این قضیه رو دقیق متوجه نشدم
:)
فرض کنیم interface میگه باید یک متد ()void A باشه. حالا یک کلاسی این متد ()void A رو داره. دلش میخواد void A اش public باشه، یا internal باشه. ربطی که به interface نداره. به interface ربطی نداره که کلاس دلش میخواد ()void A اش رو همه ببینند یا نبینند. فقط میگه با اینترفیس من سازگار باشه یعنی ()void A رو داشته باشه. از طرف دیگه interface رو میتونید مخفی کنید، فرضا بگید نمیخوام کسی بیرون از اسمبلی کد خودم از این interface استفاده کنه، اینکه دلتون میخواد از interface چه کسانی استفاده کنند یه بحث کاملا جدا است. ربطی به متد های داخلش که نداره. مثال زدم تا ببینید، یک کلاس میتونست چندین متد X داشته باشه، که هر کدوم با یک interface جدا قابل دسترسی اند. دیدید که کامپایلر نمیگه چرا چند تا X داره. اون X خود متد هم کاملا مستقل از اینها بود. اگر شما دسترسی کسی رو به IFirst محدود کنید، فرضا protected اش کنید، چطوری میتونه IFirst.X رو فراخوانی کنه؟ نمیتونه. این به این معنی نیست که interface خودش دسترسی پذیر نیست، به این معنی ئه که ربطی به دسترسی متد های داخلش نداره، چون پیاده سازی شون نکرده که بخواد براشون سطح دسترسی تعیین کنه.

میدونم . سئوالم چیز دیگه ای بود
سئوالم اینه که رابطه ی متد Sort که درون کلاس List هست ، با اعضای پیاده سازی شده ی اینترفیس IComparable (یعنی متد CompareTo) در کلاس Dog چیه؟
یعنی وقتی اینترفیس IComparable در کلاس Dog پیاده سازی شد ، متد Sort چجوری میفهمه که باید متد CompareTo در کلاس Dog رو فراخونی کنه؟
نمیدونم منظورهام رو تونستم برسونم یا نه
خیلی ساده، با is می توانید چک کنید که یک شیء ای با یک موردی سازگار هست یا نه، فرضا (<x is IComparable<Dog) چک می کنه که آیا x قابلیت مقایسه با Dog رو پیاده سازی کرده یا خیر.
دیدید چطور IFirst.X رو فراخوانی کردم؟ همانطور هم Sort میتونه IComparable<Dog>.CompareTo رو فراخوانی کنه. که البته همه این موارد رو بجای Dog با T انجام میده، چون Generic ئه.


درباره ی اینترفیس IComparer هم سئوالی داشتم و اینکه وقتی اورلود متد Sort مربوط به این اینترفیس رو مقداردهی میکنیم ، مگه نباید یک شی ای از فرزندان این اینترفیس رو بهش بدیم؟ آخه اینترفیس که شی قبول نمیکنه . پس اشکال کد زیر ، یعنی اشکال خط myVar.Sort(a); چیه؟ :

کد:
        public class Dog : IAnimal, IComparer
        {
            private string name;

            public Dog(string name)
            {
                this.Name = name;
            }

            public string Describe()
            {
                return "Hello, I'm a dog and my name is " + this.Name;
            }

            public int Compare(object x, object y)
            {
                MessageBox.Show(x.ToString() + "\n" + y.ToString());
                return 5;
            }

            public string Name
            {
                get { return name; }
                set { name = value; }
            }
        }



        interface IAnimal
        {
            string Describe();

            string Name
            {
                get;
                set;
            }
        }

حالا در رویدادی ، در فرم1 (اشکال اون خطی که گفتم در کد زیر ، چیه؟) :


کد:
        private void btnInterface1_Click(object sender, EventArgs e)
        {
            List<Page2Class.Dog> myVar = new List<Page2Class.Dog>();
            Page2Class.Dog a = new Page2Class.Dog("jorg_10");
            myVar.Add(a);
            myVar.Add(new Page2Class.Dog("jorg_2"));
            myVar.Add(new Page2Class.Dog("jorg_1"));
            myVar.Add(new Page2Class.Dog("abc"));

            myVar.Sort(a);

            foreach (Page2Class.Dog item in myVar)
            {
                MessageBox.Show(item.Name);
            }
        }

میگه نمیتونه نوع Dog رو به IComparer تبدیل کنه!
Dog که فرزند IComparer هه . نیاز به تبدیل نباید داشته باشه
و کلا اینکه کد بالا رو چجوری میشه درست کرد؟
بد ساختیدش آخه، شما IComparer چی رو ساختید؟ یک IComparer عمومی که هر object ای قبول می کنه. Sort اینو نمیخواد. شما مگه میتونید int رو با Dog یا Dog رو با Button مقایسه کنید؟ چیزی رو بسازید که میتونید و چیزی که Sort لازم داره. در ضمن IComparer رو از کلاس تون جدا کنید، منطقی نیست که شما یک Dog جدید بسازید که باهاش Dog ها رو با هم مقایسه کنید، مگر اینکه بگید این Dog داور یا قاضی ئه. منطقی نیست چون مشخصات Dog ئه اینجا هیچ کاربردی نداره. یک کلاس جدا براش درنظر بگیرید :
کد:
    class DogComparer : IComparer<Dog>
    {
        public int Compare(Dog x, Dog y)
        {
            MessageBox.Show(x.ToString() + "\n" + y.ToString());
            return 5;
        }
    }

کد:
            myVar.Sort(new DogComparer());
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ممنون استاد علی . درباره ی پست بالا ، بیشتر بررسی میکنم و بعدا سئوال میپرسم :)
ولی الان یه مشکلی که قبلا با NuGet برای نصب کنسول UnmanagedExports توی نسخه ی ویژال استودیو 2017 داشتم ، هنوزم هست . ارور زیر رو میده که نمیدونم چیه . راهی برای حل مشکلش هست؟ :

1.JPG
البته نسخه ی ویژال استودیو ام 15.2 هست . نسخه ی 15.3 شو دارم ولی نصب نکردم ولی فکر نکنم توی 15.3 هم درست شده باشه؟ حالا نمیدونم ویژال استودیوی 2017 با NuGet سازگار نیست یا NuGet با اون !
نسخه ی NuGet دانلود شده هم 1.2.7 بود . نمیدونم نسخه ی جدیدترش هم اومد یا نه؟
کلا میشه توی ویژال استودیوی 2017 این قضیه رو درست کرد؟ اگه آره ، چجوری؟

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

ویرایش : این مشکل ، با نصب ویژال استودیو 2017 نسخه ی 15.3 در ویندوز 7 ، حل شد . حالا نمیدونم مشکل از نسخه ی 15.2 ویژال استودیو بود یا از ویندوز 10 ام !
ممنون
 
آخرین ویرایش:

the_king

مدیرکل انجمن
ممنون استاد علی . درباره ی پست بالا ، بیشتر بررسی میکنم و بعدا سئوال میپرسم :)
ولی الان یه مشکلی که قبلا با NuGet برای نصب کنسول UnmanagedExports توی نسخه ی ویژال استودیو 2017 داشتم ، هنوزم هست . ارور زیر رو میده که نمیدونم چیه . راهی برای حل مشکلش هست؟ :

مشاهده پیوست 111962
البته نسخه ی ویژال استودیو ام 15.2 هست . نسخه ی 15.3 شو دارم ولی نصب نکردم ولی فکر نکنم توی 15.3 هم درست شده باشه؟ حالا نمیدونم ویژال استودیوی 2017 با NuGet سازگار نیست یا NuGet با اون !
نسخه ی NuGet دانلود شده هم 1.2.7 بود . نمیدونم نسخه ی جدیدترش هم اومد یا نه؟
کلا میشه توی ویژال استودیوی 2017 این قضیه رو درست کرد؟ اگه آره ، چجوری؟

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

ویرایش : این مشکل ، با نصب ویژال استودیو 2017 نسخه ی 15.3 در ویندوز 7 ، حل شد . حالا نمیدونم مشکل از نسخه ی 15.2 ویژال استودیو بود یا از ویندوز 10 ام !
ممنون
به احتمال زیاد UnmanagedExports تون نسخه قدیمی تری بوده، مجددا که نصبش کردید نسخه جدید رو دانلود کرده.
 

SajjadKhati

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


شما یک static class بسازید و یک فیلدی داخلش بسازید، این کلاس همیشه یک نمونه static ئه و مقدارش فیلد اش هم همیشه یک نمونه است، نمیشه دو تا نمونه با دو تا مقدار متفاوت برای اون فیلد وجود داشته باشه.
حالا اگه شما این نمونه رو داخل یک متغیر قرار بدید و کپی کنید در یک متغیر دیگه، چی کپی میشه؟ Reference اش. یعنی همچنان یک نمونه داریم با همون یک مقدار برای فیلد. هر تغییری در مقدار فیلد بدید در هر دو متغیر همون مقدار رو می بینید. اما اگه static struct بود چی؟ شما به محض اینکه مقدار struct رو از یک متغیر به متغیر دیگه ای کپی می کردید کل حافظه static ئه کپی میشد، یعنی دیگه یک نمونه نبود، دو تا میشد. این با اصل ذات static بودنش در تناقض ئه، اگر مقدار فیلد رو در یک متغیر عوض می کردید در دومی مقدار فیلد همچنان مقدار قبلی میبود. برای همینه که نمیشه static struct ای وجود داشته باشه، چون static بودن با Value Type بودنش جور در نمیاد.
ممنون
لطفا به جاهایی از این تقل قول که بولد کردم ، دقت کنید چون ابهامات زیادی از این گفته تون برام پیش اومد
منظورتون از "این کلاس همیشه یک نمونه static ئه" ،دقیقا چی هه؟ الان برای من ، این جمله ، چند مفهوم انتزاعی و تفسیر پذیر داره . برداشت اول این میتونه باشه که کلاس استاتیک مون ، یک شی رو برمیگردونه . چون نه میشه از کلاس استاتیک ، شی درست کرد و نه میشه اون کلاس رو بصورت مستقیم داخل متغییری ریخت . قطعا این برداشتم غلطه . برداشت بعدی اینه که یک عضو و فیلد استاتیک ای داشته باشه این کلاس . باز هم از اون فیلد نمیشه شی درست کرد . بجز اینکه مقدار بازگشتی اون فیلد رو که شی برمیگردونه ، رو نمونه حساب کنیم . کلا من این تیکه رو اصلا متوجه نشدم
به هر حال ، نزدیک ترین تفسیر این میتونه باشه که منظورتون اینه که یک کلاس استاتیک ای ، یک عضو داده ای استاتیک داره . این عضو رو توی متغییری میریزیم و بعد اون متغییر رو دوباره در متغییر دیگه ای میریزیم (فرض ام درسته؟) . حالا با این فرض ، ادامه میدیم :

همینجا خودش ، باز یه سئوال پیش میاد . اینکه تا جایی که میدونم ، value type یا reference type بودن یک داده ، ربطی به این نداره که اون چیز (منظورم مقدار اعضا هست . مثلا مقداری که فیلد یا پروپرتی برمیگردونه) داخل کلاس هست یا استراکچر بلکه به این ربط داره که اون چیز (عضو) ، خودش چه مقدار بازگشتی ای داره . اگه نوع بازگشتی اون عضو (هر عضو . فرقی نمیکنه که توی استراکچر تعریف شده باشه یا توی کلاس) ، از نوع کلاس بود ، reference type هه وگرنه value type هه . الان این قضیه درست هه؟ اگه غلط هه ، مثلا یه استراکچری تعریف کنید که یه فیلدی از نوع بازگشتی StringBuilder داشته باشه (فعلا در این مثال درباره ی استاتیک بودن ، حرف نمیزنم . یعنی هم استراکچر و هم این عضو ، عضو معمولی باشن) . شی از استراکچر درست کنین و مقدار این عضو (که نوع بازگشتی StringBuilder داره) رو توی یه متغییر جدیدی بریزین . دوباره همین متغییر رو توی یه متغییر دیگه بریزین . حالا توسط یکی از متغییرها ، یک کاراکتر از شی StringBuilder رو تغییر بدین . حالا دیده میشه که هر دو متغییر ، مقدارشون تغییر کرد . یا توی یک کلاس ، نوع int رو میشه چک کرد

حالا برگردیم به ادامه ی بحث
خوب ، با این چیزی که گفتید یعنی "
حالا اگه شما این نمونه رو داخل یک متغیر قرار بدید و کپی کنید در یک متغیر دیگه، چی کپی میشه؟" ؛ طبق مسئله ای که در بالا گفتم ، به نظرم value type بودن به این ربط داره که اون متغییر یا عضو مون ، خودش از نوع استراکچر و کلاس هست یا نیست ، نه اینکه توی کلاس یا استراکچر تعریف شده باشه یا نباشه . دوما اینکه این طور باشه ، که هست (یعنی دو مقدار مجزا در دو متغییر باشن) ؛ اشکالش چی هست مگه؟ همونطور که در پاراگراف بالا این قضیه رو گفتم ، مشکل و تناقضی با استاتیک بودن نداره . اگه هم تناقض با استاتیک بودن داشته باشه ، اولا خوب اعضای استاتیک (و استراکچر) درون کلاس هم همینطور هستن و دوما اعضای استاتیک (و از نوع مقدار بازگشتی استراکچر) که داخل استراکچر هستن هم همین طورن پس سئوال مهم اینه که وقتی اعضای درون استراکچر هم میتونن استاتیک باشن (با وجود همین نکته ی کپی شدن مقدار که گفتین) ، پس خود استراکچر چرا نمیتونه استاتیک باشه؟ (یعنی همون برگشتیم به سئوال اولo_O)

مگه سوال در مورد static بودن interface و اعضاء اش نبود؟ گفتم که ماهیت interface رو درست درک نکردید. پیاده سازی نداره که static باشه. static interface یعنی چی؟ خودتون میتونید تعریفش کنید بگید چیه؟ مگه شما میتوانستید با new از interface شی بسازید که حالا static اش کنید تا نشه ازش شیء ساخت؟ مگه interface ها فیلدی داشتن که بهشون حافظه static اختصاص بده؟ interface که خودش پیاده سازی نداره که بخواهیم اعضاء اش رو static کنیم.
آها ممنون متوجه شدم

فرض کنیم interface میگه باید یک متد ()void A باشه. حالا یک کلاسی این متد ()void A رو داره. دلش میخواد void A اش public باشه، یا internal باشه. ربطی که به interface نداره. به interface ربطی نداره که کلاس دلش میخواد ()void A اش رو همه ببینند یا نبینند. فقط میگه با اینترفیس من سازگار باشه یعنی ()void A رو داشته باشه. از طرف دیگه interface رو میتونید مخفی کنید، فرضا بگید نمیخوام کسی بیرون از اسمبلی کد خودم از این interface استفاده کنه، اینکه دلتون میخواد از interface چه کسانی استفاده کنند یه بحث کاملا جدا است. ربطی به متد های داخلش که نداره. مثال زدم تا ببینید، یک کلاس میتونست چندین متد X داشته باشه، که هر کدوم با یک interface جدا قابل دسترسی اند. دیدید که کامپایلر نمیگه چرا چند تا X داره. اون X خود متد هم کاملا مستقل از اینها بود. اگر شما دسترسی کسی رو به IFirst محدود کنید، فرضا protected اش کنید، چطوری میتونه IFirst.X رو فراخوانی کنه؟ نمیتونه. این به این معنی نیست که interface خودش دسترسی پذیر نیست، به این معنی ئه که ربطی به دسترسی متد های داخلش نداره، چون پیاده سازی شون نکرده که بخواد براشون سطح دسترسی تعیین کنه.
خوب منم تقریبا همین رو میگم ولی شما در مثال تون ، در کلاس Test ، عضو X در اینترفیس های IFirst و ISecand رو جداگانه پیاده سازی (explicitly implement) کردید (که باید در این صورت برای دسترسی به عضو X مربوط به هر اینرفیس ، نوع داده ای هم از همون اینترفیس باشه) . اتفاقا سئوالی که فراموش کردم بپرسم هم همین هست که چرا وقتی در همین مثالی که زدید ، وقتی جداگانه برای هر اینترفیس میخوایم در کلاس فرزندش پیاده سازی کنیم ، دوباره نباید سطح دسترسی براش تعریف کنیم (در کلاس فرزند) ولی اگه بخوایم implicitly implement کنیم ، حتما باید سطح دسترسی شو public بگیریم؟


خیلی ساده، با is می توانید چک کنید که یک شیء ای با یک موردی سازگار هست یا نه، فرضا (<x is IComparable<Dog) چک می کنه که آیا x قابلیت مقایسه با Dog رو پیاده سازی کرده یا خیر.
دیدید چطور IFirst.X رو فراخوانی کردم؟ همانطور هم Sort میتونه IComparable<Dog>.CompareTo رو فراخوانی کنه. که البته همه این موارد رو بجای Dog با T انجام میده، چون Generic ئه.


بد ساختیدش آخه، شما IComparer چی رو ساختید؟ یک IComparer عمومی که هر object ای قبول می کنه. Sort اینو نمیخواد. شما مگه میتونید int رو با Dog یا Dog رو با Button مقایسه کنید؟ چیزی رو بسازید که میتونید و چیزی که Sort لازم داره. در ضمن IComparer رو از کلاس تون جدا کنید، منطقی نیست که شما یک Dog جدید بسازید که باهاش Dog ها رو با هم مقایسه کنید، مگر اینکه بگید این Dog داور یا قاضی ئه. منطقی نیست چون مشخصات Dog ئه اینجا هیچ کاربردی نداره. یک کلاس جدا براش درنظر بگیرید :
کد:
    class DogComparer : IComparer<Dog>
    {
        public int Compare(Dog x, Dog y)
        {
            MessageBox.Show(x.ToString() + "\n" + y.ToString());
            return 5;
        }
    }

کد:
            myVar.Sort(new DogComparer());
آها ممنون
تا حدود زیادی متوجه شدم ولی باید تمرین بیشتری رو انجام بدم تا کامل درک کنم
ولی سئوالی که پیش میاد اینه که چطور متوجه شدید که اینترفیس IComparer ، جنریک هست؟ اصلا موقع تعریفش که علائمی از جنریک بودن نداره . وقتی هم IComparer رو مینویسم و جلوش علامت > میذارم ، توی اینتل لایسنس مینویسه in T که مفهموش نمیدونم چیه! (تا حالا همچین عبارتی ندیدم)
بعد از کجا متوجه شدید که در آرگومان متد Compare ، نوع object رو باید به Dog تغییر بدید (احیانا تغییر ندادن اش که مشکلی ایجاد نمیکنه؟)
 

the_king

مدیرکل انجمن
ممنون استاد علی
اینو میدونم
منظورم این بود ، با این حال هنوز دقیقا متوجه نشدم که چرا وقتی nullable میکنیم یک استراکچر رو ، اعضاش چرا بصورت عادی لیست نمیشه و باید توسط پروپرتی value بهش دسترسی داشت؟
اگه خودتون ساختار Nullable رو ببینید میینید که فقط یک struct ساده است، ارتباط اش با struct ای که Nullable می کنه در همین حد ئه که نوع فیلد هاش با اون منطبق ئه، وارث اش که نیست. Nullable کردن یک struct به این معنی نیست که ساختار struct عوض بشه. همچین چیزی نیست. فقط یک محفظه میذاره دورش که انگار روش برچسب بخوره محتویاتم Null هست یا نیست، فقط همین. لپ تاپ دسته نداره، بخوان با دسته بردارنش میذارنش تو یه کیف دسته دار، این کیف که ساختار لپ تاپ رو عوض نمی کنه، فقط یک محفظه دور اونه. شما از بیرون این محفظه که نمیتونید با محتویاتش کار کنید، کیف لپ تاپ نه دکمه Power داره و نه تاچ پد. اون struct ئه هم داخل یک struct دیگه مورد استفاده قرار میگیره، خود struct داخلی رو که ویرایش نکرده. وارث اش هم که نیست، یک struct مجزا است، دلیلی نداره اعضاء struct ای رو لیست کنه که وارث اش نیست.

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

ایراد از توضیح منه، من چون موقع شرح دادن از Reflection ذهنیت قبلی دارم چیزی رو میگم در واقعیت پشت پرده هست، هر موجودیتی در System.Reflection هم قابلیت دریافت اطلاعات و مشخصاتش هست و هم قابلیت دسترسی به اعضاء اش و فراخوانی شون. کلاس static هم مثل سایر نمونه هاست، منحصر بفرد و یکتا هست، اما باز یک نمونه است و مثل سایر نمونه ها در دسترس ئه، نه به شیوه متفاوتی.
اگه میشد ازش شی درست کرد که دیگه static نبود. اما نمونه داره، با Type اش به نمونه اش دسترسی دارید، همونطور که در مورد نمونه های عادی اشیاء دسترسی دارید :
کد:
    public static class Test
    {
        public static int V = 1;
    }
کد:
            var t1 = typeof(Test);
            var t2 = t1;
            var v1 = (int)t1.GetField("V").GetValue(null);
            t2.GetField("V").SetValue(null, 2);
            var v2 = (int)t1.GetField("V").GetValue(null);
            Test.V = 3;
            var v3 = (int)t1.GetField("V").GetValue(null);
            MessageBox.Show(string.Format("v1 = {0},   v2 = {1},   v3 = {2}", v1, v2, v3));
Type کلاس ئه، اما به هر حال فرقی نمی کنه که var t2 = t1 باشه یا var t2 = typeof(Test) و هر دو نتیجه اش یکسانه.
این کلاس static نمونه ای داره که چه مستقیم از طریق نام کلاس اش و چه غیر مستقیم از طریق Type کلاس اش بهش دسترسی دارید. ازش نمونه جدیدی هم ساخته نمیشه. یک نمونه خاص و منحصر بفرد ئه. Clone کردنی هم نیست، تمامی رفرنس ها به یک نمونه واحد ئه.


به هر حال ، نزدیک ترین تفسیر این میتونه باشه که منظورتون اینه که یک کلاس استاتیک ای ، یک عضو داده ای استاتیک داره . این عضو رو توی متغییری میریزیم و بعد اون متغییر رو دوباره در متغییر دیگه ای میریزیم (فرض ام درسته؟) . حالا با این فرض ، ادامه میدیم :


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

بله، همینطوره، یک پروپرتی از نوع Button همیشه Reference Type ئه، چه داخل class باشه و چه داخل struct و بالعکس، یک پروپرتی از نوع Point همیشه Value Type ئه، چه داخل class باشه و چه داخل struct

حالا برگردیم به ادامه ی بحث
خوب ، با این چیزی که گفتید یعنی "
حالا اگه شما این نمونه رو داخل یک متغیر قرار بدید و کپی کنید در یک متغیر دیگه، چی کپی میشه؟" ؛ طبق مسئله ای که در بالا گفتم ، به نظرم value type بودن به این ربط داره که اون متغییر یا عضو مون ، خودش از نوع استراکچر و کلاس هست یا نیست ، نه اینکه توی کلاس یا استراکچر تعریف شده باشه یا نباشه . دوما اینکه این طور باشه ، که هست (یعنی دو مقدار مجزا در دو متغییر باشن) ؛ اشکالش چی هست مگه؟ همونطور که در پاراگراف بالا این قضیه رو گفتم ، مشکل و تناقضی با استاتیک بودن نداره . اگه هم تناقض با استاتیک بودن داشته باشه ، اولا خوب اعضای استاتیک (و استراکچر) درون کلاس هم همینطور هستن و دوما اعضای استاتیک (و از نوع مقدار بازگشتی استراکچر) که داخل استراکچر هستن هم همین طورن پس سئوال مهم اینه که وقتی اعضای درون استراکچر هم میتونن استاتیک باشن (با وجود همین نکته ی کپی شدن مقدار که گفتین) ، پس خود استراکچر چرا نمیتونه استاتیک باشه؟ (یعنی همون برگشتیم به سئوال اولo_O)
نشد که، static بودن باید تضمین کنه که این مورد static مربوط به یک نمونه خاص از بین نمونه های متعدد نیست. فرضا اگه در struct یا class ای یک فیلد static تعریف می کنید هزار تا هم نمونه از این struct یا class داشته باشید داخل هیچکدوم شون اون فیلد رو ندارند، جزو هیچکدوم شون نیست. امتحان کنید، تو تنظیمات Properties پروژه تون بخش Build ، تنظیم Allow unsafe code رو فعال کنید و همچین کدی رو امتحان کنید، ببینید سایز struct هاتون به حافظه فیلد های static شون ربط داره یا نه :
کد:
        public struct S1
        {
            public static int i1;
            public static int i2;
            public static int i3;
            public static int i4;
            public static int i5;
            public static int i6;
            public static int i7;
            public static int i8;
            public int j;
        }

        public struct S2
        {
            public static int i1;
            public int j1;
            public int j2;
            public int j3;
            public int j4;
            public int j5;
            public int j6;
            public int j7;
            public int j8;
        }
کد:
            unsafe
            {
                MessageBox.Show(string.Format("S1 = {0},    S2 = {1}", sizeof(S1), sizeof(S2)));
            }
فراموش نکنید که struct نوع خاصی از class ئه. اگر قرار باشه struct در رفتار تفاوتی نسبت به class ایجاد نکنه که اصلا ماهیتش زیر سوال میره. static struct چه کاربرد خاصی باید داشته باشه؟ ازش چه ویژگی خاصی توقع دارید که در static class نباشه؟ شما تصور می کنید وقتی دارید مقدار یک متغیر struct رو در یک متغیر دیگه کپی می کنید میاد از مقدار فیلد static کپی می گیره؟ اصلا متعلق به اون شی نیست که بخواد کپی اش بگیره. اعضاء static داخل struct مستقل از حافظه اون struct هایی هستند که میسازید. و اون حافظه مربوط به فیلد های static هم نمیتونه Value Type باشه چون به Reference احتیاج داره. شما اگه یه struct خالی هم بسازید میینید که 1 بایت طول داره، چون حافظه تخصیصی به یک موجودیت که نمیتونه 0 بایت باشه، حداقلش رو بهش میده. حالا شما میخواهید static struct ای بسازید که نه فیلد غیر static میتونه داشته باشه و نه حتی یک بایت حافظه میتونه داشته باشه و نه Value Type بودنش براش معنی داره. الان اگه کامپایلر بهتون اجازه میداد static struct بسازید میپرسیدید که چرا اجازه میده struct ای ساخته بشه که قابل استفاده نیست؟ و این static struct به چه درد میخوره وقتی هیچ مزیتی نسبت به static class نداره؟

آها ممنون متوجه شدم

خوب منم تقریبا همین رو میگم ولی شما در مثال تون ، در کلاس Test ، عضو X در اینترفیس های IFirst و ISecand رو جداگانه پیاده سازی (explicitly implement) کردید (که باید در این صورت برای دسترسی به عضو X مربوط به هر اینرفیس ، نوع داده ای هم از همون اینترفیس باشه) . اتفاقا سئوالی که فراموش کردم بپرسم هم همین هست که چرا وقتی در همین مثالی که زدید ، وقتی جداگانه برای هر اینترفیس میخوایم در کلاس فرزندش پیاده سازی کنیم ، دوباره نباید سطح دسترسی براش تعریف کنیم (در کلاس فرزند) ولی اگه بخوایم implicitly implement کنیم ، حتما باید سطح دسترسی شو public بگیریم؟
فرزندش نه، پیاده سازیش. اینترفیس فرزند نداره. اینکه دو تا کلاس متفاوت یک اینترفیس واحد رو پیاده سازی کردن به این معنی نیست که باباشون یکی ئه، صرفا یک متد هایی رو هر دو دارند.
چون اون متد که explicit پیاده سازی شده وابسته به یک Interface ئه، IFirst.X نمینونه یک اسم مجاز برای متد های public باشه که بگید کاری به Interface ندارم و مستفیما ازش استفاده می کنم. عملی نیست. همانطور که در لیست متد های کلاس جای X رو نمیگیره و تونستم X رو به عنوان یک متد عادی جداگانه تعریف کنم. شما به هر حال از بیرون کلاس نمی توانستید اون متد IFirst.X رو به عنوان متد های کلاس اسم ببرید. دسترسی اش در حد private میشه، حالا به Interface اش دسترسی داشته باشید میتونید با وجود private بودن ازش استفاده کنید، دسترسی نداشته باشید نمی توانید. برای همین خود متد اش ضمنی private میشه و دسترسی نمی پذیره.
 

the_king

مدیرکل انجمن
آها ممنون
تا حدود زیادی متوجه شدم ولی باید تمرین بیشتری رو انجام بدم تا کامل درک کنم
ولی سئوالی که پیش میاد اینه که چطور متوجه شدید که اینترفیس IComparer ، جنریک هست؟ اصلا موقع تعریفش که علائمی از جنریک بودن نداره . وقتی هم IComparer رو مینویسم و جلوش علامت > میذارم ، توی اینتل لایسنس مینویسه in T که مفهموش نمیدونم چیه! (تا حالا همچین عبارتی ندیدم)
بعد از کجا متوجه شدید که در آرگومان متد Compare ، نوع object رو باید به Dog تغییر بدید (احیانا تغییر ندادن اش که مشکلی ایجاد نمیکنه؟)
خودتون که قبلا داشتید با Generic Type ها کار می کردید، یادتون که نرفته؟ میخواستید به زور string اش کنید که گفتم string یک نوع خاصه، اگه قرار باشه فقط string باشه که دیگه Generic Type نمیشه. اینم شبیه همونه، Generic Class ئه، Generic Interface ئه، Generic Struct ئه. یک نوع عمومی نامشخص به اسم T تعیین می کنید که موقع استفاده تعیین میشه. مثلا شما نوشتید <List<Dog ، تو پیاده سازی List هر جا T بوده بجاش Dog جایگزین شده. فلسفه اش اینه، یک مدل کلی کد نویسی کنید، بعد با انواع داده های مختلف استفاده کنید. بجای اینکه بیایید برای int و double و float و string کلاس های List مجزا بسازید که همه شون شبیه هم باشند و فقط نوع داده شون فرق کنه یه دونه Generic اش رو بنویسید.
شما اول یه نگاه به تعریف کلاس اش بندازید :
کد:
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
یک نگاهی به نحوه استفاده اش بندازید :
کد:
List<dog> dogs = new List<dog>();
بعد یک نگاه به تعریف Sort بندازید :
کد:
        public void Sort();
        public void Sort(Comparison<T> comparison);
        public void Sort(IComparer<T> comparer);
        public void Sort(int index, int count, IComparer<T> comparer);
مساله اینه که Sort دنبال یک مقایسه گر برای Dog vs ِDog می گرده. یا باید خود اعضاء <IComparable<Dog رو پیاده سازی کرده باشن یا IComparable (مقایسه گر پیشفرض) ای پیاده سازی کرده باشن که از عهده مقایسه Dog با Dog بر بیاد یا یه <IComparer<Dog بهش معرفی کنید. شما اومدید در خود اعضاء IComparer ئه object vs object رو پیاده سازی کردید، Sort از این IComparer استفاده نمی کنه، چون متدی با تعریف
Sort(IComparer comparer) نداره. مساله این نیست که Compare شما از عهده اش برنمیومد، چیزی ساخته بودید که Sort تو جستجو اش محل نمیذاشت و روش حساب باز نمی کرد و به هر حال ازش استفاده نمی کرد.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
استاد علی ، پست های بالا رو بعدا راجع بهش بحث میکنم
درباره ی قضیه ی کلاس Dog و متد Sort در کلاس List<T> ، این چیزایی که میگم ، درسته؟ :
در بدنه متد Sort (فعلا اوذلودی از این متد که هیچ ورودی ای نمیگیره ، مد نظرمه) در کلاس List ، پیش فرض اینه که زمانی این متد Sort فراخونی میشه که شی ای که از کلاس T (مثلا شی Dog) به List داده میشه ، قطعا درون کلاس T ، اینترفیس IComparable یا اینترفیس جنریک IComparable رو پیاده سازی کرده باشه
درسته؟
بنابراین در بدنه اش باید این جور پیاده سازی ای شده باشه (اون خط مهم اش منظورمه) که عضو خاص از این شی کلاس List (که عضو خاص اش همون شی ای از نوع T میشه) رو به اینترفیس IComparable (یا جنریک خاص از این اینترفیس) تبدیل میکنه . بعد متد CompareTo اش رو فراخونی میکنه هر بار یعنی :

کد:
((IComparable)this[0]).CompareTo(object obj)

بعد حالا 2 تا سئوال پیش میاد
اول اینکه ورودی obj در کد بالا رو چه مقداری میده؟ آخه متد Sort با اورلودی که هیچ آرگومان رو دریافت نکنه ، چیزی از کاربر نگرفت که به این متد CompareTo پاس بده
دوم اینکه در این اورلود از متد Sort ، میتونه شی this[0] رو به اینترفیس IComparable تبدیل نکنه دیگه؟ چون خود شی this[0] از نوع T هست پس قطعا متد CompareTo رو پیاده سازی کرد .

کلا درباره ی نوع فراخونی و مقداردهی متد CompareTo که داخل در اورلودهای مختلف متد Sort انجام گرفت ، بیشتر توضیح میدین؟ اگه میشه ، با دلیل
ممنون
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بعد اینکه ، اینترفیس های معروف و کاربردی رو میگین کدوم هان؟
من اینا رو میگم درسته؟ :
IEnumerable برای حلقه ی foreach هه
IDisposable برای متد Dispose که باعث پاک کردن شی در حافظه ی هیپ توسط GC میشه
IQueryable نمیدونم
INotifyPropertyChange نمیدونم
IComparable and IComparer برای متد Sort و مقایسه کردن
IEquatable and IEqualityComparer نمیدونم
IList and ICollection برای ایجاد لیست و کالکشن
IDictionary برای ایجاد دیکشنری (2 مقدار همزمان)

اونایی که نمیدونم ، توی یه سایت انگلیسی اومد و توضیح داد ولی متوجه نشدم زیاد
بجز اینا ، باز کدوم اینترفیس ها مهم ان و توضیح میدین؟
ممنون
 

the_king

مدیرکل انجمن
سلام
استاد علی ، پست های بالا رو بعدا راجع بهش بحث میکنم
درباره ی قضیه ی کلاس Dog و متد Sort در کلاس List<T> ، این چیزایی که میگم ، درسته؟ :
در بدنه متد Sort (فعلا اوذلودی از این متد که هیچ ورودی ای نمیگیره ، مد نظرمه) در کلاس List ، پیش فرض اینه که زمانی این متد Sort فراخونی میشه که شی ای که از کلاس T (مثلا شی Dog) به List داده میشه ، قطعا درون کلاس T ، اینترفیس IComparable یا اینترفیس جنریک IComparable رو پیاده سازی کرده باشه
درسته؟
بنابراین در بدنه اش باید این جور پیاده سازی ای شده باشه (اون خط مهم اش منظورمه) که عضو خاص از این شی کلاس List (که عضو خاص اش همون شی ای از نوع T میشه) رو به اینترفیس IComparable (یا جنریک خاص از این اینترفیس) تبدیل میکنه . بعد متد CompareTo اش رو فراخونی میکنه هر بار یعنی :

کد:
((IComparable)this[0]).CompareTo(object obj)

بعد حالا 2 تا سئوال پیش میاد
اول اینکه ورودی obj در کد بالا رو چه مقداری میده؟ آخه متد Sort با اورلودی که هیچ آرگومان رو دریافت نکنه ، چیزی از کاربر نگرفت که به این متد CompareTo پاس بده
ممنون
چیزی لازم نیست از کاربر دریافت کنه، شما یه مجموعه داخل List دارید که باید مرتب بشه، از هر الگوریتم مرتب سازی ای هم استفاده کنه یه مقایسه داره بین a و b که هر دو اعضاء ای از همون لیست هستند،
با a.CompareTo(b) مقایسه انجام میشه دیگه. چه چیزی لازم داره که در اختیار نداشته باشه؟ مجموعه رو و متد مقایسه رو لازم داره که هر دو رو هم داره.

دوم اینکه در این اورلود از متد Sort ، میتونه شی this[0] رو به اینترفیس IComparable تبدیل نکنه دیگه؟ چون خود شی this[0] از نوع T هست پس قطعا متد CompareTo رو پیاده سازی کرد .

چه ربطی داره. T یک نوع داده نامشخص برای List که الزاما هم Sort شدنی نیست. یعنی ممکنه از قابلیت Sort اصلا استفاده نشه. اصلا الزامی وجود نداره که T اینترفیس خاصی رو پیاده سازی کرده باشه.
کلا درباره ی نوع فراخونی و مقداردهی متد CompareTo که داخل در اورلودهای مختلف متد Sort انجام گرفت ، بیشتر توضیح میدین؟ اگه میشه ، با دلیل
دلیل چی؟ اگه مرتب کردن بر اساس مقایسه گر پیشفرض خود شیء باشه، یعنی کد نویس نخواد از مقایسه و مرتب سازی اختصاصی ای استفاده کنه که پارامتر وارد نمیشه و حالا اگه اون نوع داده مورد نظر مقایسه گر اختصاصی شیء با شیء داشته در اولویت ئه و اگه نباشه از object vs object استفاده می کنه (سربار داره چون کند تر ئه) و اگه اونم نباشه خطا میده. ولی اگه برای مرتب کردن متد و روش خاصی مد نظر کد نویس باشه باید مشخص اش کنه. فرضا بخواد int ها رو نزولی مرتب کنه.
 

the_king

مدیرکل انجمن
بعد اینکه ، اینترفیس های معروف و کاربردی رو میگین کدوم هان؟
من اینا رو میگم درسته؟ :
IEnumerable برای حلقه ی foreach هه
IDisposable برای متد Dispose که باعث پاک کردن شی در حافظه ی هیپ توسط GC میشه
اون همه در موردشون صحبت کردیم، بازم آخرش حرف اشتباه اولیه خودتون رو می زنید. حافظه شیء در هر صورت توسط GC مدیریت میشه و ربطی به IDisposable و Dispose هم نداره. چه پیاده سازی شون بکنید و چه نکنید مسئول حافظه شیء GC ئه و وقتی دیگه بهش دسترسی وجود نداشت و با تاخیر GC حافظه شو آزاد می کنه. این مساله هیچ ربطی به Dispose نداره. حافظه این همه کلاس و شیء که Disposable رو پیاده سازی نکرده اند رو کی آزاد می کنه؟ هر چند بار هم Dispose رو اجرا کنید شیء به خودی خود سر جاشه و حافظه اش هم همینطور. Dispose هیچ موقع حافظه خود شیء رو نمیتونه آزاد کنه، خودش متدی از شیء ئه. در این مورد قبلا خیلی صحبت کردیم. اون Heap رو هم من نگفتم، بهتره جایی هم عنوانش نکنید چون هیچ تضمینی وجود نداره که Heap باشه. من نه تاییدش می کنم و نه ذکر کردنش رو توصیه می کنم. اگه شما طراح GC بودید و پیاده سازیش با شما بوده، حرفی نیست، وگرنه دلیلی نداره در مورد موضوعی صحبت بشه که نه معتبر ئه و نه برای کد نویس زبان #C اطلاعاتش مفید و موثر ئه. اینکه حافظه GC از نظر داخلی از چه ساختاری ئه مثل اینه که بخواهید در داروخانه فرمول شیمیایی دارو رو برای بیمار تشریح کنید، چیزی رو بگید که مفید باشه و بدرد بخوره. حالا اطلاعات اشتباه باشه یا نباشه بماند.


IQueryable نمیدونم
INotifyPropertyChange نمیدونم
IComparable and IComparer برای متد Sort و مقایسه کردن
IEquatable and IEqualityComparer نمیدونم
IList and ICollection برای ایجاد لیست و کالکشن
IDictionary برای ایجاد دیکشنری (2 مقدار همزمان)

اونایی که نمیدونم ، توی یه سایت انگلیسی اومد و توضیح داد ولی متوجه نشدم زیاد
بجز اینا ، باز کدوم اینترفیس ها مهم ان و توضیح میدین؟
ممنون
هر چی I توی Framework ئه مهم ئه، اگه مهم و پر استفاده نبود که داخل Framework نمیذاشتن. کلا ماهیت Framework با کتابخانه های دیگه فرق اش در همینه که چیزهایی که وجودشون ضروری ئه یا پر استفاده و مرسوم ئه داخلش قرار میگیره. اینکه کدوم بیشتر استفاده میشه به موضوع پروژه و البته تسلط برنامه نویس بستگی داره. هر چقدر برنامه نویس به امکانات موجود بیشتر مسلط باشه و بشناستشون بیشتر ازشون استفاده می کنه.
 

SajjadKhati

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

اگه خودتون ساختار Nullable رو ببینید میینید که فقط یک struct ساده است، ارتباط اش با struct ای که Nullable می کنه در همین حد ئه که نوع فیلد هاش با اون منطبق ئه، وارث اش که نیست. Nullable کردن یک struct به این معنی نیست که ساختار struct عوض بشه. همچین چیزی نیست. فقط یک محفظه میذاره دورش که انگار روش برچسب بخوره محتویاتم Null هست یا نیست، فقط همین. لپ تاپ دسته نداره، بخوان با دسته بردارنش میذارنش تو یه کیف دسته دار، این کیف که ساختار لپ تاپ رو عوض نمی کنه، فقط یک محفظه دور اونه. شما از بیرون این محفظه که نمیتونید با محتویاتش کار کنید، کیف لپ تاپ نه دکمه Power داره و نه تاچ پد. اون struct ئه هم داخل یک struct دیگه مورد استفاده قرار میگیره، خود struct داخلی رو که ویرایش نکرده. وارث اش هم که نیست، یک struct مجزا است، دلیلی نداره اعضاء struct ای رو لیست کنه که وارث اش نیست.
بازم من دقیق متوجه نشدم :green: حالا بماند اشکال نداره . لازم به توضیح مجدد نیست

ایراد از توضیح منه، من چون موقع شرح دادن از Reflection ذهنیت قبلی دارم چیزی رو میگم در واقعیت پشت پرده هست، هر موجودیتی در System.Reflection هم قابلیت دریافت اطلاعات و مشخصاتش هست و هم قابلیت دسترسی به اعضاء اش و فراخوانی شون. کلاس static هم مثل سایر نمونه هاست، منحصر بفرد و یکتا هست، اما باز یک نمونه است و مثل سایر نمونه ها در دسترس ئه، نه به شیوه متفاوتی.
اگه میشد ازش شی درست کرد که دیگه static نبود. اما نمونه داره، با Type اش به نمونه اش دسترسی دارید، همونطور که در مورد نمونه های عادی اشیاء دسترسی دارید :
کد:
    public static class Test
    {
        public static int V = 1;
    }
کد:
            var t1 = typeof(Test);
            var t2 = t1;
            var v1 = (int)t1.GetField("V").GetValue(null);
            t2.GetField("V").SetValue(null, 2);
            var v2 = (int)t1.GetField("V").GetValue(null);
            Test.V = 3;
            var v3 = (int)t1.GetField("V").GetValue(null);
            MessageBox.Show(string.Format("v1 = {0},   v2 = {1},   v3 = {2}", v1, v2, v3));
Type کلاس ئه، اما به هر حال فرقی نمی کنه که var t2 = t1 باشه یا var t2 = typeof(Test) و هر دو نتیجه اش یکسانه.
این کلاس static نمونه ای داره که چه مستقیم از طریق نام کلاس اش و چه غیر مستقیم از طریق Type کلاس اش بهش دسترسی دارید. ازش نمونه جدیدی هم ساخته نمیشه. یک نمونه خاص و منحصر بفرد ئه. Clone کردنی هم نیست، تمامی رفرنس ها به یک نمونه واحد ئه.
آها تازه با کلاس ها در فضای نام System.Reflection آشنا شدم . قابلیت خیلی خوبی هه . باهاش میشه توسط رشته (که شامل اطلاعات اون عضو هست مثلا شامل نام کلاس هست) ، از اون کلاس شی ساخت یا کلا اطلاعات اعضاش رو بدست آورد . ولی ای کاش برعکسش هم شدنی بود یعنی میشد یک رشته گرفت و مقدار اون رشته رو همون نام یک متغییر کرد . البته این قضیه رو قبلا پرسیدم ولی کلا انگار نمیشه
ولی ویژال استودیو که مثلا نام یک دکمه ای که خودمون بصورت دستی توی پروژه اضافه میکنیم رو که این رشته رو به نام متغییر تبدیل میکنه و کدهاشو اتوماتیک مینویسه ، با زبان های سطح پایین تر انجام میده؟


بله، همینطوره، یک پروپرتی از نوع Button همیشه Reference Type ئه، چه داخل class باشه و چه داخل struct و بالعکس، یک پروپرتی از نوع Point همیشه Value Type ئه، چه داخل class باشه و چه داخل struct


نشد که، static بودن باید تضمین کنه که این مورد static مربوط به یک نمونه خاص از بین نمونه های متعدد نیست. فرضا اگه در struct یا class ای یک فیلد static تعریف می کنید هزار تا هم نمونه از این struct یا class داشته باشید داخل هیچکدوم شون اون فیلد رو ندارند، جزو هیچکدوم شون نیست. امتحان کنید، تو تنظیمات Properties پروژه تون بخش Build ، تنظیم Allow unsafe code رو فعال کنید و همچین کدی رو امتحان کنید، ببینید سایز struct هاتون به حافظه فیلد های static شون ربط داره یا نه :
کد:
        public struct S1
        {
            public static int i1;
            public static int i2;
            public static int i3;
            public static int i4;
            public static int i5;
            public static int i6;
            public static int i7;
            public static int i8;
            public int j;
        }

        public struct S2
        {
            public static int i1;
            public int j1;
            public int j2;
            public int j3;
            public int j4;
            public int j5;
            public int j6;
            public int j7;
            public int j8;
        }
کد:
            unsafe
            {
                MessageBox.Show(string.Format("S1 = {0},    S2 = {1}", sizeof(S1), sizeof(S2)));
            }
فراموش نکنید که struct نوع خاصی از class ئه. اگر قرار باشه struct در رفتار تفاوتی نسبت به class ایجاد نکنه که اصلا ماهیتش زیر سوال میره. static struct چه کاربرد خاصی باید داشته باشه؟ ازش چه ویژگی خاصی توقع دارید که در static class نباشه؟ شما تصور می کنید وقتی دارید مقدار یک متغیر struct رو در یک متغیر دیگه کپی می کنید میاد از مقدار فیلد static کپی می گیره؟ اصلا متعلق به اون شی نیست که بخواد کپی اش بگیره. اعضاء static داخل struct مستقل از حافظه اون struct هایی هستند که میسازید. و اون حافظه مربوط به فیلد های static هم نمیتونه Value Type باشه چون به Reference احتیاج داره. شما اگه یه struct خالی هم بسازید میینید که 1 بایت طول داره، چون حافظه تخصیصی به یک موجودیت که نمیتونه 0 بایت باشه، حداقلش رو بهش میده. حالا شما میخواهید static struct ای بسازید که نه فیلد غیر static میتونه داشته باشه و نه حتی یک بایت حافظه میتونه داشته باشه و نه Value Type بودنش براش معنی داره. الان اگه کامپایلر بهتون اجازه میداد static struct بسازید میپرسیدید که چرا اجازه میده struct ای ساخته بشه که قابل استفاده نیست؟ و این static struct به چه درد میخوره وقتی هیچ مزیتی نسبت به static class نداره؟
من نمیدونم چرا متوجه ی ربط سئوال و جواب نمیشم
دلیلش میتونه این باشه که چون کلاس های استاتیک ، از هیچ کلاسی جز object نمیتونن ارث بری کنن (البته جد هیچ کلاسی هم نمیشن) ، ولی استراکچرها نیز دارن فرزند کلاس System.ValueType ها بشن پس به همین دلیل ، یک استراکچر نمیتونه استاتیک باشه؟ دلیلش درسته؟


فرزندش نه، پیاده سازیش. اینترفیس فرزند نداره. اینکه دو تا کلاس متفاوت یک اینترفیس واحد رو پیاده سازی کردن به این معنی نیست که باباشون یکی ئه، صرفا یک متد هایی رو هر دو دارند.
چون اون متد که explicit پیاده سازی شده وابسته به یک Interface ئه، IFirst.X نمینونه یک اسم مجاز برای متد های public باشه که بگید کاری به Interface ندارم و مستفیما ازش استفاده می کنم. عملی نیست. همانطور که در لیست متد های کلاس جای X رو نمیگیره و تونستم X رو به عنوان یک متد عادی جداگانه تعریف کنم. شما به هر حال از بیرون کلاس نمی توانستید اون متد IFirst.X رو به عنوان متد های کلاس اسم ببرید. دسترسی اش در حد private میشه، حالا به Interface اش دسترسی داشته باشید میتونید با وجود private بودن ازش استفاده کنید، دسترسی نداشته باشید نمی توانید. برای همین خود متد اش ضمنی private میشه و دسترسی نمی پذیره.
آها اینترفیس فرزند نداره ؛ فقط پیاده سازی داره
بازم من دقیق متوجه نشدم
خوب حالا گیرم که اینترفیس ها ، سطح دسترسی ندارن . واسه همین ، موقع پیاده سازی بصورت explicitly ، اونجا هم سطح دسترسی رو مشخص نمیکنیم ولی با این حال من هنوز متوجه نشدم چرا موقع پیاده سازی بصورت implicitly ، مجبوریم سطح دسترسی شو public بگیریم؟!! چرا نمیذاره مثلا internal بگیریم؟
البته دسترسی پیاده سازی بصورت explicitly ، در همون کلاس ، private هم نیست . فقط با نوع داده ای اینترفیس قابل دسترس هست . توی خود همون کلاس چون نوع داده ای از همون کلاس هست (یعنی با شی this) ، در دسترس نیست
بعد اینکه من متوجه نشدم که چرا میگین اینترفیس چون پیاده سازی نداره ، سطح دسترسی براش معین نمیکنن در صورتی که اعضای abstract هم پیاده سازی ندارن ولی سطح دسترسی برش مشخص میکنن؟ (یعنی این سئوال مو که قبلا پرسیدم ، هنوز به جواب نرسیدم)


خودتون که قبلا داشتید با Generic Type ها کار می کردید، یادتون که نرفته؟ میخواستید به زور string اش کنید که گفتم string یک نوع خاصه، اگه قرار باشه فقط string باشه که دیگه Generic Type نمیشه. اینم شبیه همونه، Generic Class ئه، Generic Interface ئه، Generic Struct ئه. یک نوع عمومی نامشخص به اسم T تعیین می کنید که موقع استفاده تعیین میشه. مثلا شما نوشتید <List<Dog ، تو پیاده سازی List هر جا T بوده بجاش Dog جایگزین شده. فلسفه اش اینه، یک مدل کلی کد نویسی کنید، بعد با انواع داده های مختلف استفاده کنید. بجای اینکه بیایید برای int و double و float و string کلاس های List مجزا بسازید که همه شون شبیه هم باشند و فقط نوع داده شون فرق کنه یه دونه Generic اش رو بنویسید.
شما اول یه نگاه به تعریف کلاس اش بندازید :
کد:
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
یک نگاهی به نحوه استفاده اش بندازید :
کد:
List<dog> dogs = new List<dog>();
بعد یک نگاه به تعریف Sort بندازید :
کد:
        public void Sort();
        public void Sort(Comparison<T> comparison);
        public void Sort(IComparer<T> comparer);
        public void Sort(int index, int count, IComparer<T> comparer);
مساله اینه که Sort دنبال یک مقایسه گر برای Dog vs ِDog می گرده. یا باید خود اعضاء <IComparable<Dog رو پیاده سازی کرده باشن یا IComparable (مقایسه گر پیشفرض) ای پیاده سازی کرده باشن که از عهده مقایسه Dog با Dog بر بیاد یا یه <IComparer<Dog بهش معرفی کنید. شما اومدید در خود اعضاء IComparer ئه object vs object رو پیاده سازی کردید، Sort از این IComparer استفاده نمی کنه، چون متدی با تعریف
Sort(IComparer comparer) نداره. مساله این نیست که Compare شما از عهده اش برنمیومد، چیزی ساخته بودید که Sort تو جستجو اش محل نمیذاشت و روش حساب باز نمی کرد و به هر حال ازش استفاده نمی کرد.
آها وقتی میگه شی ای از IComparer<int> رو بده ، یعنی شی ای از کلاسی که توی اون کلاس ، IComparer<int> رو پیاده سازی کردی رو بده نه اینکه فقط IComparer رو تنهایی پیاده سازی کرده باشه
میگم ، متد Sort (ای که هیچ آرگومان ورودی دریافت نمیکنه) در کلاس List ، تخمینا باید یه همچین پیاده سازی ای داشته باشه . درسته؟ :

ادامه در پست بعد
 

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

بالا