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

the_king

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

کد:
55-67
که برابر
کد:
55+(-67)
حساب میکنیم ، اونا هم همینطوره؟

بله، روش مکمل دو (متمم دو) اینطوریه.

پس یعنی مثلا جواب عبارت اعداد باینری زیر درسته؟
کد:
10-1 => 10+(-1)
-1 => 00000001 => 11111110 => 11111111
10 + 11111111 = 100000001
پس جواب این ، باید بشه 257 ؟ درسته؟!
نه دیگه، اگر من هم بگم درسته شما نباید قبول کنید که 257 = 1 - 2 و قاعدتا خودتون باید جوابی که باید بهش برسید رو بدونید، شما 00000001 (عدد یک) رو از 00000010 (عدد 2) کسر کرده اید، پس جواب باید 00000001 (عدد یک) باشه و هر جواب دیگه ای محاسبه کنید، یک جای کار ایراد داره
تبدیل 1- بر اساس مکمل دو (متمم دو) را درست انجام داده اید، ایراد در جمع نهایی ئه. وقتی شما از حافظه 8 بیتی برای مکمل 2 استفاده می کنید، باید جمع نهایی تون هم 8 بیتی باشه، نه 9 بیتی. اون بیت سر ریز شده نهم رو در نتیجه قرار ندهید. مقدار حاصل جمع 00000001 (عدد 1) ئه، نه 100000001 (عدد 257)
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
میگم استاد علی ، آموزشای سی شارپ رو تقریبا استارت زدم . در اون تاپیک نام افراد رو نبردم چون خیلی ها بهم کمک کردن (چون در انجمن های مختلف میذارم واسه همین ممکنه با از قلم افتادن نام افراد ، کدورت پیش بیاد) ولی تنها کسی که نقش بسیار اساسی در کمکم داشت ، شما بودین که چندین باره ازتون تشکر میکنم :rose:
------------------------
سئوالم اینه که این درسته که در سی شارپ ، هر داده ای ، یک داده ی پیش فرض داره؟ یعنی همونطور که اعداد اعشاری بصورت پیش فرض از نوع double اند ، اعداد رند هم از نوع int اند؟ واسه همینه که وقتی از نوع داده ای short یا byte متغییری رو میگیریم ، برای اعمال عملیات ریاضی (جمع و کم و ...) باید باز هم به نوع مورد نظر (short و ...) تبدیل کنیم که نوع int این کار ها رو نیاز نداره یعنی باید بنویسیم :

کد:
byte a = 2;
            byte b = 6;
            byte c = (byte)(a + b);
یعنی با اونکه ما a و b رو از نوع byte گرفتیم ولی باز موقع محاسبه در مقدار c ، این a و b مون رو از نوع int میگیره که باید دوباره کل شو به byte تعریف کنیم. درسته؟
بعد اینکه نمیدونم این سئوال رو ازتون پرسیدم یا نه ولی چرا یه متغییر محلی رو وقتی تعریف میکنیم و مقدار اولیه نمیدیم ، مقدارش null هست ولی متغییر سراسری رو همین کار رو که میکنیم ، مقدار اولیه شو داره؟! توجیه علمی اش چیه؟
ممنون
 

the_king

مدیرکل انجمن
سئوالم اینه که این درسته که در سی شارپ ، هر داده ای ، یک داده ی پیش فرض داره؟ یعنی همونطور که اعداد اعشاری بصورت پیش فرض از نوع double اند ، اعداد رند هم از نوع int اند؟ واسه همینه که وقتی از نوع داده ای short یا byte متغییری رو میگیریم ، برای اعمال عملیات ریاضی (جمع و کم و ...) باید باز هم به نوع مورد نظر (short و ...) تبدیل کنیم که نوع int این کار ها رو نیاز نداره یعنی باید بنویسیم :
کد:
byte a = 2;
            byte b = 6;
            byte c = (byte)(a + b);
یعنی با اونکه ما a و b رو از نوع byte گرفتیم ولی باز موقع محاسبه در مقدار c ، این a و b مون رو از نوع int میگیره که باید دوباره کل شو به byte تعریف کنیم. درسته؟

تمامی انواع داده value type مقدار پیشفرض دارند. سایر انواع داده هم که چون null پذیر اند null مقدار پیشفرض شونه. اعداد اعشاری بصورت پیشفرض double اند مگر اینکه با حروف کلیدی نوع دیگه ای رو مشخص کنید :
کد:
            var f = 1.23f;  //float
            var d = 1.23d;  //double
            var m = 1.23m;  //decimal
            var l = 123L; //long
البته تمامی انواع داده این حروف کلیدی پسوند رو ندارند.
عملیاتی که روی بایت ها انجام میشه نتیجه اش int ئه، یعنی شما به هر حال یک int تحویل می گیرید که بعدا می توانید به byte تبدیل بکنید یا نکنید. دلیلش اینه که اصلا در ماشین مجازی CLR محاسباتی برای byte و short تعریف نشده و جزو انواع داده اساسی ماشین نیستند.

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

SajjadKhati

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

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

SajjadKhati

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

the_king

مدیرکل انجمن
ممنون استاد علی
منظورتون از کلمه ی "فاقد مقدار خواهد بود" همون یعنی null هست دیگه؟ درسته؟
راستی ، ما که توی متغییر سراسری ، کنار نوع متغییر مورد نظر (مثلا نوع int و ...) ، علامت سئوال نذاشتیم تا شی استراکچر (شی int) ما رو null پذیر کنه . پس چرا وقتی شی ای از این نوع (int) رو بصورت متغییر محلی که مینویسیم ، مقدار پیش فرض اش null هست؟
نه، فاقد مقدار متغیری ئه که هنوز مقدار دهی نشده، uninitialized ئه. مثلا متغیر محلی ;int a رو تعریف می کنید ولی مقداری بهش نمی دهید. اگر سعی کنید مقدار ازش بخوانید چون فاقد مقدار ئه کامپایلر ایراد می گیره.
این متغیر x نه null پذیر ئه و نه مقدار پیشفرض اش null ئه، بصورت پیشفرض مقدار 0 داره. :
کد:
    public partial class Class1
    {
        private int x;
    }

این متغیر y میتونه null باشه و null پذیر ئه و مقدار پیشفرض اش هم null ئه :
کد:
    public partial class Class2
    {
        private int? y;
    }

این متغیر z میتونه null باشه و null پذیر ئه ولی مقدار دهی اولیه نشده و هنوز مقداری نداره، نه مقدار null و نه مقدار دیگری :
کد:
    public partial class Class3
    {
        private void Test()
        {
            int? z;
            var m = z; //Error
        }

این متغیر i نمیتونه null باشه و null پذیر نیست و مقدار دهی اولیه هم نشده و هنوز مقداری نداره :
کد:
    public partial class Class4
    {
        private void Test()
        {
            int i;
            var m = i; //Error
        }
دقت کنید که تفاوت در متغیر محلی بودن و نبودن ئه، متغیر محلی تا مقدار دهی نشه مقدار نداره و نمیشه ازش مقداری خوند.
 

SajjadKhati

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

کد:
public partial class Class2
    {
        private int? y;
    }
منتها چون من بجای int در بالا ، string گذاشته بودم و حواسم به استراکچر و کلاس بودن شون نبود (که کلاس ها کلا null پذیرند) و ارور داده بود ، واسه همین گفتم که حالا متوجه شدم
الان مثلا در کدی که در بالا نوشتین :

کد:
private void Test()
        {
            int? z;
            var m = z; //Error
        }

یعنی چی که این z نه null هست و نه مقدار پیش فرض داره؟ خوب مقدار بهش ندیم و null پذیر باشه ، null میشه دیگه؟!! یعنی مقدارش پوچ هست یعنی اصلا توی رم این متغییر وجود نداره دیگه؟!! واسه همین متغییر z داخل متغییر m نمیتونه ریخته شه .این جمله درست نیست مگه؟
اگه این جمله غلط هست ، پس در واقع مقدارش چی هست؟ یعنی وقتی نه مقدار داشته باشه و نه null باشه ، پس قضیه ی سوم ، چی میتونه باشه؟!
 

the_king

مدیرکل انجمن
ممنون
منظورم همون کد دوم که در پست بالا بود ، دادین هست یعنی :

کد:
public partial class Class2
    {
        private int? y;
    }
منتها چون من بجای int در بالا ، string گذاشته بودم و حواسم به استراکچر و کلاس بودن شون نبود (که کلاس ها کلا null پذیرند) و ارور داده بود ، واسه همین گفتم که حالا متوجه شدم
الان مثلا در کدی که در بالا نوشتین :

کد:
private void Test()
        {
            int? z;
            var m = z; //Error
        }

یعنی چی که این z نه null هست و نه مقدار پیش فرض داره؟ خوب مقدار بهش ندیم و null پذیر باشه ، null میشه دیگه؟!! یعنی مقدارش پوچ هست یعنی اصلا توی رم این متغییر وجود نداره دیگه؟!! واسه همین متغییر z داخل متغییر m نمیتونه ریخته شه .این جمله درست نیست مگه؟
اگه این جمله غلط هست ، پس در واقع مقدارش چی هست؟ یعنی وقتی نه مقدار داشته باشه و نه null باشه ، پس قضیه ی سوم ، چی میتونه باشه؟!
قضیه سوم یک مقدار نامشخص غیر قابل پیش بینی ئه،
اون حافظه ای که به متغیر تخصیص داده میشه قبلا متعلق به متغیر های دیگه بوده، از قبل مقداری داخلش هست که غیر قابل پیش بینی ئه. و چون موقع تخصیص به متغیر جدید مقدار قبلی پاک نمیشه، این تلاش برای خوندن مقدارش قطعا سهوی بوده و نتیجه یک اشتباه در کد نویسی ئه. در زبان هایی مثل ++C خیلی مرسوم ئه که اشتباها مقدار متغیری رو میخونند قبل از اینکه مقداری بهش بدهند و هر بار که برنامه اجرا میشه مقدار های متفاوتی از داخل حافظه خونده میشه. ممکنه برنامه یکبار درست کار کنه و یکبار اشتباه. برای همین کامپایلر #C نمیخواد روال کد از حالت قطعی دربیاد و با خطا جلوی این دسترسی پیش از موعد رو میگیره.

نمیشه که یک متغیر هم تعریف بشه و هم در حافظه جایی نداشته باشه، اگه حافظه ای بهش تخصیص داده نشده باشه که دیگه متغیر نیست. null یه مقدار ئه، مقدار قابل استفاده ای نیست ولی فضا اشغال می کنه.
در رشته های string انتهای رشته عموما با کاراکتر Null مشخص میشه، همین null یک کاراکتر ئه با کد صفر و خودش یک خونه از حافظه رشته رو اشغال کرده، مقدار ئه، جا میگیره.
وقتی شما یک اشاره گر 32 بیتی دارید، 32 بیت حافظه رو صرف این اشاره گر کرده اید، چه یک آدرس حافظه معتبر داخلش باشه و چه مقدار Null (همون آدرس صفر) به هر حال 32 بیت ئه اشغال شده، اون Null هم یک مقدار ئه مثل هر آدرس حافظه ای.
از نظر فنی z مقداری داره که از قبل در حافظه بوده و ربطی به z نداشته. ابدا null نیست، چون حقیقت اینه که متغیر int نمیتونه null باشه. اون ?int یک فیلد به نوع داده اضافه کرده تا اینطوری قابلیت null پذیر بودن رو بهش اضافه کنه.
کامپایلر اجازه دسترسی به z رو نمیده چون مقدارش قابل پیش بینی نیست، اجرا شدنش روال کد رو تصادفی و ناپایدار می کنه. برای همین مجبورتون می کنه که اول بهش مقدار بدهید، حتی اگه بخواهید null داخلش قرار بگیره باید خودتون اینکار رو بکنید، برای متغیر محلی بصورت خودکار مقدار پیشفرض ای ثبت نمیشه.
 

SajjadKhati

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

نمیشه که یک متغیر هم تعریف بشه و هم در حافظه جایی نداشته باشه، اگه حافظه ای بهش تخصیص داده نشده باشه که دیگه متغیر نیست. null یه مقدار ئه، مقدار قابل استفاده ای نیست ولی فضا اشغال می کنه.
در رشته های string انتهای رشته عموما با کاراکتر Null مشخص میشه، همین null یک کاراکتر ئه با کد صفر و خودش یک خونه از حافظه رشته رو اشغال کرده، مقدار ئه، جا میگیره.
وقتی شما یک اشاره گر 32 بیتی دارید، 32 بیت حافظه رو صرف این اشاره گر کرده اید، چه یک آدرس حافظه معتبر داخلش باشه و چه مقدار Null (همون آدرس صفر) به هر حال 32 بیت ئه اشغال شده، اون Null هم یک مقدار ئه مثل هر آدرس حافظه ای.
از نظر فنی z مقداری داره که از قبل در حافظه بوده و ربطی به z نداشته. ابدا null نیست، چون حقیقت اینه که متغیر int نمیتونه null باشه. اون ?int یک فیلد به نوع داده اضافه کرده تا اینطوری قابلیت null پذیر بودن رو بهش اضافه کنه.
کامپایلر اجازه دسترسی به z رو نمیده چون مقدارش قابل پیش بینی نیست، اجرا شدنش روال کد رو تصادفی و ناپایدار می کنه. برای همین مجبورتون می کنه که اول بهش مقدار بدهید، حتی اگه بخواهید null داخلش قرار بگیره باید خودتون اینکار رو بکنید، برای متغیر محلی بصورت خودکار مقدار پیشفرض ای ثبت نمیشه.

ممنون استاد علی :rose:
تا یه حدودی متوجه شدم
پس null همون مقدار صفر هست که مثلا توی نوع char میخوایم null بدیم همون مقدار 0\ رو میذاریم
اگه اشتباه نکنم ، طبق توضیحات تون این طور فهمیدم :
مثلا وقتی یه یه متغییری (فرضا از نوع کلاس) تعریف میکنیم بنابراین اون متغییر اشاره گری میشه (اشاره میکنه) به اون مقدار کلاس (که در حافظه ی هیپ هست) . بعد به هر دلیلی که اون متغییر اشاره گرش رو از دست بده ، clr اون مقدار رو از رم آزاد میکنه اما محتواش رو پاک نمیکنه . واسه ی همین وقتی یه متغییر دیگه تعریف میکنیم (و مقدار نمیدیم) ، ممکنه همون خونه های آزاد شده ی متغییر قبلی نصیبش بشه (یا بخشی از اون خونه های متغییر قبلی) که بنابراین داخلش از قبل مقدار جای داره . اما سی شارپ تا به این متغییر جدید ، خودمون مقدار ندیم ، نمیذاره بهش دسترسی پیدا کنیم چون حاوی اطلاعاتی نیست که خودمون خواسته باشیم
درسته؟
آخه قبلا یکی از اساتیدهای دیگه (در جای دیگه) گفته بودش که داخل سی شارپ ، تا وقتی مقدار ندیم به متغییر ، اصلا حافظه ای براش توی رم نمیگیره که تا حالا فکر میکردم این طوره
---------------
بعد اینکه اگه بخوایم یه متغییری (یا آرایه و ...) ای رو توی سی شارپ ، بعد از اینکه مقدارش رو null دادیم یا کلا هر متغییری که اشاره گرش رو از دست داد ، فورا از رم آزاد بشه ، چه دستوری باید نوشت؟
میدونم که clr خودش بعد از از دست دادن اشاره گر یه متغییر به مقدارش ، رم رو آزاد میکنه ولی قبلا گفته بودین که این کار رو ممکنه فوری انجام نده و هر وقت که صلاح دونست انجام بده .
ولی برای اینکه فوری حافظه رو آزاد کنه باید چی کار کرد؟ مثلا این کار موقع خوندن فایل های بزرگ خیلی به درد میخوره که حافظه باید در سریعترین زمان ممکن ، آزاد بشه
مثلا توی لوا ، بعد از nil کردن متغییر (همون null کردن در سی شارپ) ، فقط کافی هست که دستور گربک کالکتور رو بزنیم و تابع collectgarbage() رو با هیچ آرگومانی اجرا کنیم . در این صورت ، هر چی متغییر null یا اشاره گر از دست رفته رو همون لحظه از رم آزاد میکنه
توی سی شارپ باید چی کار کرد؟
 

the_king

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

درسته.

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

به حرف اساتید کاری نداشته باشید، خودتون امتحان کنید. ببینید وقتی متغیر های محلی ایجاد می شوند و هنوز مقدار دهی نشده اند آیا حافظه مصرفی برنامه تغییری میکنه یا نه :
TestVariableMemory.zip

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

پیوست ها

  • TestVariableMemory.zip
    68.6 کیلوبایت · بازدیدها: 5

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ممنون
با تابع GC.GetTotalMemory میشه فهمید چقدر از رم در برنامه ی سی شارپ مون استفاده شده؟
اگه آره ، پس من چرا خیلی متغییر میدم ، تقریبا فرق خاصی نداره؟ متغییرهام حداقل باید یک بایت بیشتر اشغال میکردن
 

the_king

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

SajjadKhati

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


کد:
private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData==(Keys.Control | Keys.ControlKey | Keys.LControlKey))
            {
                MessageBox.Show("");
            }
        }

کد بالا کار نمیکنه
با e.KeyCode هم کدش چطور میشه ؟
-------------------------------
میگم این enum ای که مایکروسافت میخواست براش بسازه (key) ، اعضاشو چرا این جوری به ترتیب اعداد عادی گرفت؟ یعنی چرا به ترتیب اعداد دودویی یعنی 1 ، 2، 4، 8، 16، 32 و ... نگرفت؟ این جوری که اصلا اند کردن مقدار e.kaydata با اعضای kay (برای اینکه بدونیم چه ترکیبی برای کلید فشرده شده داره) که جواب نمیده و ممکنه اشتباه بده جواب رو . درست میگم دیگه؟ یعنی عملگر & روی اعداد باینری درست جواب میده دیگه؟
مثلا در کد زیر :
کد:
int[] myOperation = new int[10];
            myOperation[0] = 1;
            myOperation[1] = 2;
            myOperation[2] = 3;
            myOperation[3] = 4;
            myOperation[4] = 5;
            myOperation[5] = 6;
            myOperation[6] = 7;
            myOperation[7] = 8;
            myOperation[8] = 9;
            myOperation[9] = 10;

            int orResault = myOperation[7] | myOperation[8];


            for (int i=0; i < myOperation.Length; i++)
            {
                int andResault = orResault & myOperation[i];
                MessageBox.Show(andResault.ToString());
            }
با اونکه عدد 8 و 9 اور شدند ولی جواب اند ، آخرین عضو هم میده و بقیه ی اعضا هم علاوه بر 0 ، جواب 1 هم میده .
 
آخرین ویرایش:

the_king

مدیرکل انجمن
ممنون
پس ساده ترین کدی که میشه فهمید برنامه ی سی شارپ مون چقدر رم مصرف میکنه ، چیه؟

مثل سایر زبان ها، از سیستم عامل گزارش مصرف حافظه Process برنامه تون رو می گیرید، من تو اون مثال TestVariableMemory.zip از System.Diagnostics.Process.GetCurrentProcess().WorkingSet64 استفاده کردم که میزان حافظه RAM فیزیکی ئه، غیر از این VirtualMemorySize64 هم هست که حافظه مجازی برنامه است.
به این نکته توجه کنید که مدیریت حافظه سیستم عامل و GC مدام در حال تغییر این مقادیر اند، سیستم عامل مدام RAM فیزیکی به برنامه ها میده و ازشون میگیره. GC هم که مدام مشغول جمع آوری حافظه های بلا استفاده است.
حتی اگه کدی هم در برنامه اجرا نشه باز هم دلیل بر ثابت شدن این مقادیر نیست.


بعد اینکه اگه بخوام در رویداد keydown و با e.keydata کدی بنویسم که فقط کلید کنترل سمت چپ زده شد ، کد اجرا بشه ، باید چی بنویسم؟


کد:
private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData==(Keys.Control | Keys.ControlKey | Keys.LControlKey))
            {
                MessageBox.Show("");
            }
        }

کد بالا کار نمیکنه
با e.KeyCode هم کدش چطور میشه ؟
پیاده سازی NET. بین کلید های کنترل چپ و راست تفاوتی قائل نیست، دلیل اش نمی دونم چی بوده، باگ هم نیست ولی از فلسفه اش بی اطلاعم.
کد:
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern Int16 GetAsyncKeyState(Keys vKey);

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData == (Keys.Control | Keys.ControlKey) & (GetAsyncKeyState(Keys.LControlKey) < 0))
            {
                MessageBox.Show("");
            }
        }


-------------------------------
میگم این enum ای که مایکروسافت میخواست براش بسازه (key) ، اعضاشو چرا این جوری به ترتیب اعداد عادی گرفت؟ یعنی چرا به ترتیب اعداد دودویی یعنی 1 ، 2، 4، 8، 16، 32 و ... نگرفت؟ این جوری که اصلا اند کردن مقدار e.kaydata با اعضای kay (برای اینکه بدونیم چه ترکیبی برای کلید فشرده شده داره) که جواب نمیده و ممکنه اشتباه بده جواب رو . درست میگم دیگه؟ یعنی عملگر & روی اعداد باینری درست جواب میده دیگه؟
مثلا در کد زیر :
کد:
int[] myOperation = new int[10];
            myOperation[0] = 1;
            myOperation[1] = 2;
            myOperation[2] = 3;
            myOperation[3] = 4;
            myOperation[4] = 5;
            myOperation[5] = 6;
            myOperation[6] = 7;
            myOperation[7] = 8;
            myOperation[8] = 9;
            myOperation[9] = 10;

            int orResault = myOperation[7] | myOperation[8];


            for (int i=0; i < myOperation.Length; i++)
            {
                int andResault = orResault & myOperation[i];
                MessageBox.Show(andResault.ToString());
            }
با اونکه عدد 8 و 9 اور شدند ولی جواب اند ، آخرین عضو هم میده و بقیه ی اعضا هم علاوه بر 0 ، جواب 1 هم میده .
این کد کلید ها استاندارد PC ئه، یعنی قبل از اینکه مایکروسافت سیستم عامل بسازه هم اغلب شون تعریف شده بودند. از همون اول هم قرار نبوده همه کلید ها رو بشه با هم فشار داد چون هم کاربردی نداشت و هم نیاز به خروجی صفحه کلید بالای 100 بیتی بود که با امکانات سخت افزاری الان هم غیر عادیه چه برسه به اون زمان که پورت های صفحه کلید 5 پینی و 6 پینی بودند. مدار داخلی صفحه کلید تا حد امکان ساده و ارزون طرحی میشه. اگر قرار بود بشه همه کلید ها رو با هم فشار داد طبعا Keys حداقل یک 128 بیتی بود، نه 32 بیتی. تنها کد همون چند تا کلید Modifiers ئه Shift و Control و Alt هستند که باید با توان های 2 تفکیک می شدند که همینطور هم هستند. دلیل اینکه کد کلید ها با هم تداخل داره همین قضیه است که اصلا قرار نبوده با هم فشار دادنی باشند. اگه اون زمان که این استاندارد بوجود می اومد میدونستند که قراره سالها بعد توی بازی ها کلید های W A S D همزمان با سایر کلید ها فشار داده بشوند لابد اونها رو هم جزو Modifiers ها در نظر می گرفتند. سالها طول کشید که تا صفحه کلید هایی ساخته بشوند که اینجور ترکیب کلید ها رو قبول کنند.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
پیاده سازی NET. بین کلید های کنترل چپ و راست تفاوتی قائل نیست، دلیل اش نمی دونم چی بوده، باگ هم نیست ولی از فلسفه اش بی اطلاعم.
کد:
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern Int16 GetAsyncKeyState(Keys vKey);

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData == (Keys.Control | Keys.ControlKey) & (GetAsyncKeyState(Keys.LControlKey) < 0))
            {
                MessageBox.Show("");
            }
        }

ممنون :rose:
استاد علی ، از کجا متوجه شدین که توی این خط :

کد:
if (e.KeyData == (Keys.Control | Keys.ControlKey) & (GetAsyncKeyState(Keys.LControlKey) < 0))
وسط شون عملگر اند بذارین؟
مگه عملگر بیتی اور باعث نوعی ترکیب نمیشه؟ پس همینطور که برای Keys.Control و Keys.ControlKey از عملگر اور استفاده کردین که مقدار عدد هر دو رو اور و به نوعی ترکیب میکنه ، باز هم برای ترکیب کردن ، باید با شرط (GetAsyncKeyState(Keys.LControlKey) < 0 از عملگر اور استفاده میکردین که
بذارید این جوری سئوال رو بپرسم که کجاها باید از عملگر بیتی اند استفاده کرد؟ و از کجا متوجه میشید که کجاها باید استفاده کرد؟ همینطور کاربرد عملگر بیتی ایکس اور ^ رو توضیح مختصر بدین ، ممنون میشم
 

the_king

مدیرکل انجمن
ممنون :rose:
استاد علی ، از کجا متوجه شدین که توی این خط :

کد:
if (e.KeyData == (Keys.Control | Keys.ControlKey) & (GetAsyncKeyState(Keys.LControlKey) < 0))
وسط شون عملگر اند بذارین؟
مگه عملگر بیتی اور باعث نوعی ترکیب نمیشه؟ پس همینطور که برای Keys.Control و Keys.ControlKey از عملگر اور استفاده کردین که مقدار عدد هر دو رو اور و به نوعی ترکیب میکنه ، باز هم برای ترکیب کردن ، باید با شرط (GetAsyncKeyState(Keys.LControlKey) < 0 از عملگر اور استفاده میکردین که
بذارید این جوری سئوال رو بپرسم که کجاها باید از عملگر بیتی اند استفاده کرد؟ و از کجا متوجه میشید که کجاها باید استفاده کرد؟ همینطور کاربرد عملگر بیتی ایکس اور ^ رو توضیح مختصر بدین ، ممنون میشم
خیلی ساده است، ببینید شرط ها true و false ای اند یا ترکیب بیتی؟ مثلاKeys.ControlKey و Keys.Control عدد اند، | و & شون عملگر بیتی ئه، نه منطقی. true و false نیستند که & و | شون منطقی باشند.
شما نمی توانید بین true و یک عدد عملگر منطقی یا بیتی بکار ببرید چون دو طرف عملگر از یک جنس نیستند، یا باید هر دو عدد باشند یا هر دو مقدار بولی باشند. شرط GetAsyncKeyState(Keys.LControlKey) < 0 جوابش true یا false ئه. Keys.Control | Keys.ControlKey هم جوابش یک مقدار عددی ئه. ایندو تا رو نمیشه با | یا & با هم ترکیب کرد.

شرط (if (e.KeyData == (Keys.Control | Keys.ControlKey) یعنی e.KeyData ترکیب Keys.Control و Keys.ControlKey باشد. Keys.Control و Keys.ControlKey دو مقدار مستقل اند، از این جهت که اگر با | با همدیگه ترکیب بشوند مقدار حاصل نه Keys.Control ئه و نه Keys.ControlKey. اون مقدار (Keys.Control | Keys.ControlKey) هم یک مقدار ثابت ئه، متغیر که نیست. عوض که نمیشه. شما دارید e.KeyData رو با یک مقدار ثابت مقایسه می کنید. میگید اگر مقدارش دقیقا (==) ترکیب Keys.Control و Keys.ControlKey بود، پس نه Keys.Control به تنهایی و نه Keys.ControlKey به تنهایی و نه ترکیب شون با هر کلید مستقل دیگری این شرط رو true نمی کنه.

شرط if ((e.KeyData == Keys.Control) | (e.KeyData == Keys.ControlKey)) یعنی e.KeyData یا دقیقا Keys.Control باشه و یا دقیقا Keys.ControlKey باشه، نه ترکیب شون و نه ترکیب شون با کلید دیگری شرط رو true نمی کنه.

شرط if (e.KeyData == (Keys.Control | Keys.ControlKey) & (GetAsyncKeyState(Keys.LControlKey) < 0)) یعنی e.KeyData ترکیب Keys.Control و Keys.ControlKey باشد و همچنین (&) مقدار GetAsyncKeyState(Keys.LControlKey) از صفر کوچکتر باشد (Keys.LControlKey فشرده شده باشد). شما می توانید R Control را فشار دهید ولی چون شرط دوم را برقرار نمی کند حاصل if مقدار false خواهد بود.
اگر Left Control + S را فشار دهید شرط دوم برقرار خواهد بود ولی چون S را فشار داده اید شرط اول برقرار نیست و حاصل if مقدار false خواهد بود.

شرط if (e.KeyData == (Keys.Control | Keys.ControlKey) | (GetAsyncKeyState(Keys.LControlKey) < 0)) یعنی e.KeyData ترکیب Keys.Control و Keys.ControlKey باشد یا (|) مقدار GetAsyncKeyState(Keys.LControlKey) از صفر کوچکتر باشد (Keys.LControlKey فشرده شده باشد). ممکن است شما Left Control + S را فشار دهید، شرط اول برقرار نیست چون S را فشار داده اید، ولی شرط دوم برقرار است و حال if مقدار true خواهد بود.

بجای & می توانید از && استفاده کنید. مزیت && در این است که اگر شرط اول برقرار نبود، اصلا مقدار دوم را محاسبه نمی کند، چون میداند که ترکیب دو شرط به هر حال false خواهد شد و محاسبه کردن شرط دوم کار بیهوده ای است. اما قبلا هم این موضوع را مطرح کرده ام که && جدا از بحث سرعت در مواقعی بکار می روند که اجرا پذیر بودن شرط دوم در گرو شرط اول باشد مثلا ((a != null) & (a.Length > 5)) شرط مشکل سازی است، اگر a برابر null باشد تلاش برای بررسی مقدار a.Length با خطا متوقف می شود. باید حتما کاری کرد که a.Length > 5 فقط زمانی بررسی شود که a != null باشد :
کد:
((a != null) && (a.Length > 5))

عملگر xor کاربرد های متنوعی داره، میتونه برای بیت های درخواستی (یا همه بیت ها) not باشه، 1 رو 0 کنه و 0 رو 1 کنه. مثلا شما هر مقداری رو xor با 00000011 کنید دو بیت کم ارزش شون not میشه و بقیه بیت ها بدون تغییر میمونه. فرضا تبدیل حروف کوچک انگلیسی به بزرگ و تبدیل حروف انگلیسی بزرگ به کوچک با not کردن یک بیت خاص :
کد:
            var s = "MajidOnline".ToCharArray();
            for (int i = 0; i < s.Length; i++)
            {
                s[i] = (char)(s[i] ^ 32);
            }
            MessageBox.Show(new string(s));
یا میتوانید از این خاصیت اش استفاده کنید که هر مقداری با خودش xor بشه حاصل صفر میشه، فرضا از مجموعه اعداد a (صفر داخلشون نیست) یک عضو در b حذف شده، کدوم شون حذف شده؟ اگر همه اعداد موجود رو با هم xor کنیم مقادیر مشابه همدیگه رو (صفر) خنثی می کنند و فقط عددی نهایتا باقی میمونه که تک بوده. ترتیب xor ها هم اصلا مهم نیست :
کد:
  var a = new int[] { 6, 3, 5, 4, 7, 1, 2 };
  var b = new int[] { 3, 1, 7, 6, 2, 4 };
  var m = a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4] ^ a[5] ^ a[6] ^ b[0] ^ b[1] ^ b[2] ^ b[3] ^ b[4] ^ b[5];
  MessageBox.Show(m.ToString());
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ممنون استاد علی
به جان خودم لازم نیست این همه وقت بذارید و بنویسید و خسته بشد . با توضیحات کمتر هم متوجه میشم :rose:
نگاه کنید ، من سئوال فعلی ام اینه . اون شرطی رو که نوشتید :
کد:
if (e.KeyData == (Keys.Control | Keys.ControlKey) & (GetAsyncKeyState(Keys.LControlKey) < 0))
الان من از این کد این نتیجه رو میگیرم :
در قسمت :
کد:
(Keys.Control | Keys.ControlKey)
خوب مشخص هست که خروجی اش عدد میشه چون دو تا عدد رو با هم or کرد . مثلا خروجی اش 15 میشه
در قسمت :
کد:
(GetAsyncKeyState(Keys.LControlKey) < 0)
و باز هم (ابتدا) در قسمت :
کد:
(GetAsyncKeyState(Keys.LControlKey)
خروجی ، عدد میشه مثلا 17 . خوب بعد در قسمت :
کد:
(GetAsyncKeyState(Keys.LControlKey) < 0)
این عدد 17 که جایگزین میشه :
کد:
17<0
و بعد از مقایسه ، خروجی اش بولین میشه . مثلا true
خوب پس داریم :
کد:
if (e.KeyData == 15 & true)
در صورتی که همونطور که گفتین ، عدد با بولین که اند یا اور یا ایکس اور نمیشه و باید غلط بگیره . چرا غلط نمیگیره؟
در واقع از نظر من ، کد بالا با کد زیر که ارور میده ، یک ساختار رو دارن :
کد:
int a = (15 | 17) & (true);
ولی چرا اون شرط ، مثل این کد ، ارور نمیده؟!!


یا میتوانید از این خاصیت اش استفاده کنید که هر مقداری با خودش xor بشه حاصل صفر میشه، فرضا از مجموعه اعداد a (صفر داخلشون نیست) یک عضو در b حذف شده، کدوم شون حذف شده؟ اگر همه اعداد موجود رو با هم xor کنیم مقادیر مشابه همدیگه رو (صفر) خنثی می کنند و فقط عددی نهایتا باقی میمونه که تک بوده. ترتیب xor ها هم اصلا مهم نیست :
کد:
  var a = new int[] { 6, 3, 5, 4, 7, 1, 2 };
  var b = new int[] { 3, 1, 7, 6, 2, 4 };
  var m = a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4] ^ a[5] ^ a[6] ^ b[0] ^ b[1] ^ b[2] ^ b[3] ^ b[4] ^ b[5];
  MessageBox.Show(m.ToString());

آها
عجب کاربرد جالبی
فقط انگار یه دونه عضو اگه کمتر باشه رو جواب میده . یعنی اگه مثلا از آرایه ی b ، یه عضوش رو کم کنیم ، یعنی کد زیر دیگه انگار جواب مورد نظر رو نمیده :
کد:
var a = new int[] { 6, 3, 5, 4, 7, 1, 2 };
            var b = new int[] { 3, 1, 7, 6, 2 };
            var m = a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4] ^ a[5] ^ a[6] ^ b[0] ^ b[1] ^ b[2] ^ b[3] ^ b[4] ;
            MessageBox.Show(m.ToString());
یعنی در آرایه ی a ، اعداد 4 و 5 تکرار نشدن ولی جواب 1 شد
این رو کاریش میشه کرد؟
 

the_king

مدیرکل انجمن
ممنون استاد علی
به جان خودم لازم نیست این همه وقت بذارید و بنویسید و خسته بشد . با توضیحات کمتر هم متوجه میشم :rose:
نگاه کنید ، من سئوال فعلی ام اینه . اون شرطی رو که نوشتید :
کد:
if (e.KeyData == (Keys.Control | Keys.ControlKey) & (GetAsyncKeyState(Keys.LControlKey) < 0))
الان من از این کد این نتیجه رو میگیرم :
در قسمت :
کد:
(Keys.Control | Keys.ControlKey)
خوب مشخص هست که خروجی اش عدد میشه چون دو تا عدد رو با هم or کرد . مثلا خروجی اش 15 میشه
در قسمت :
کد:
(GetAsyncKeyState(Keys.LControlKey) < 0)
و باز هم (ابتدا) در قسمت :
کد:
(GetAsyncKeyState(Keys.LControlKey)
خروجی ، عدد میشه مثلا 17 . خوب بعد در قسمت :
کد:
(GetAsyncKeyState(Keys.LControlKey) < 0)
این عدد 17 که جایگزین میشه :
کد:
17<0
و بعد از مقایسه ، خروجی اش بولین میشه . مثلا true
خوب پس داریم :
کد:
if (e.KeyData == 15 & true)
در صورتی که همونطور که گفتین ، عدد با بولین که اند یا اور یا ایکس اور نمیشه و باید غلط بگیره . چرا غلط نمیگیره؟
در واقع از نظر من ، کد بالا با کد زیر که ارور میده ، یک ساختار رو دارن :
کد:
int a = (15 | 17) & (true);
ولی چرا اون شرط ، مثل این کد ، ارور نمیده؟!!
بخاطر نبودن پارانتز های اضافی ئه، کد مثل if ((e.KeyData == 15) & (true)) تفسیر میشه، نه if (e.KeyData == (15 & true)) و برای همین خطایی رخ نمیده.

آها
عجب کاربرد جالبی
فقط انگار یه دونه عضو اگه کمتر باشه رو جواب میده . یعنی اگه مثلا از آرایه ی b ، یه عضوش رو کم کنیم ، یعنی کد زیر دیگه انگار جواب مورد نظر رو نمیده :
کد:
var a = new int[] { 6, 3, 5, 4, 7, 1, 2 };
            var b = new int[] { 3, 1, 7, 6, 2 };
            var m = a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4] ^ a[5] ^ a[6] ^ b[0] ^ b[1] ^ b[2] ^ b[3] ^ b[4] ;
            MessageBox.Show(m.ToString());
یعنی در آرایه ی a ، اعداد 4 و 5 تکرار نشدن ولی جواب 1 شد
این رو کاریش میشه کرد؟
چه کاری؟ 4 و 5 رو با هم xor کنید میشه 1 که اونم درست برگردونده.هیچ نتیجه ای نمیشه گرفت جز اینکه دو مقداری که حذف شده اند همه بیت هایشان مشابه هم است بجز کم ارزش ترین بیت (قطعا مقدار یکی شان از دیگری یک واحد بزرگتر است).
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بخاطر نبودن پارانتز های اضافی ئه، کد مثل if ((e.KeyData == 15) & (true)) تفسیر میشه، نه if (e.KeyData == (15 & true)) و برای همین خطایی رخ نمیده.
ممنون
من دقیق متوجه نشدم . الان یعنی الویت عملگر == از & و | و ^ بیشتره؟ یعنی اول == رو حساب و بعد & رو محاسبه میکنه؟ مگه الویت عملگر == با = در یک حد نیست؟ اگه آره ، پس این فرض اشتباه درمیاد
اگه نه ، من قشنگ متوجه نشد . پس در این صورت اگه بخایم درست عمل کنه ، باید این طور مینوشتیم دیگه (به پرانتزها دقت کنید) :
کد:
if ( (e.KeyData == (Keys.Control | Keys.ControlKey) ) & (GetAsyncKeyState(Keys.LControlKey) < 0) )
ولی ما که این طور ننوشتیم . پس یا باید فرضیه ی بالا درست باشه (که فکر نکنم این طور باشه) یا کلا من متوجه نشدم بازم که چرا کمپایلر ارور نمیده


چه کاری؟ 4 و 5 رو با هم xor کنید میشه 1 که اونم درست برگردونده.هیچ نتیجه ای نمیشه گرفت جز اینکه دو مقداری که حذف شده اند همه بیت هایشان مشابه هم است بجز کم ارزش ترین بیت (قطعا مقدار یکی شان از دیگری یک واحد بزرگتر است).

متوجه شدم
اما بدست آوردن جواب این جوری سخت میشه که . باید خیلی از اعداد رو تست کنیم تا ببینیم کدوم عدد ، بجز کم ارزش ترین بیت شون ، کدوم بیت هاشون شبیه هم هستن . یعنی سخت میشه از عدد 1 فهمید عدد 4 و 5 با هم ایکس اور شدن
برای بدست آوردن معکوس (یعنی بدست آوردن اعدادی که ایکس اور شدن) ، مثل قضیه ی اور ، باید جواب را با دونه دونه ی اعداد ، اَند & کرد تا متوجه شد؟
------------------
درباره ی خروجی تابع GetAsyncKeyState فقط در حد اختصار توضیح میدین؟
 
آخرین ویرایش:

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

بالا