تبليغاتX
Iranian Scorpion Security Group

Iranian Scorpion Security Group

همه چیز در مورد امنیت

مقدمه اي بر سي شارپ : قسمت بيستم

Delegates

Delegates در سي شارپ روشي مطمئن و typesafe را براي بكار گيري مفهوم function pointer ارائه مي دهند. يكي از ابتدايي ترين استفاده هاي function pointers پياده سازي callback مي باشد. اما در ابتدا لازم است تا با اصول اوليه ي كاري آن آشنا شويم.

مثال يك :
يك delegate چگونه تعريف و استفاده مي شود؟
Delegate يك شيء است كه بيانگر يك تابع مي باشد بنابراين مي تواند بعنوان آرگومان ورودي يك تابع ديگر و يا عضوي از يك كلاس بكار رود.
در زبان "function-pointer" ، Func1() اشاره گري به Func2() را بعنوان پارامتر دريافت كرده و نهايتا آنرا فراخواني مي كند.
در زبان "delegate" ، Func1() يك شيء delegate از Func2() را دريافت كرده و سپس آنرا فراخواني مي كند.
در مثال زير از دو تابع براي شرح اين مطلب سود جسته شده است:
Func1() از delegate استفاده مي كند.
Func2() يك delegate است.

( شماره گذاري خطوط ، در كد زير ، صرفا براي راحت تر شدن توضيحات در مورد آنها است و لزومي به تايپ آنها در برنامه ي اصلي نيست. )

01 using System;
02 delegate void Delg(string sTry);
03 public class Example1{

// function which uses the delegate object
04 private static void Func1(Delg d){
05 d("Passed from Func1");
06 }

// function which is passed as an object
07 private static void Func2(string sToPrint){
08 Console.WriteLine("{0}",sToPrint);
09 }

// Main execution starts here
10 public static void Main(){
11 Delg d = new Delg(Func2);
12 Func1(d);
13 }
14 }

LINE 02
يك شيء delegate را براي Func2 تعريف مي كند.

LINE 04-06
تابعي را تعريف كرده است كه آرگومان ورودي آن از نوع Delg است.

LINE 07-09
تابعي را تعريف مي كند كه بايد به صورت delegate به تابع ديگر فرستاده شود.

LINE 10-14
تابع Main اجراي برنامه را با ايجاد يك شيء delegate براي Func2 آغاز كرده و سپس تابع Func1 را فراخواني مي كند.

مثال 2:
چگونه مي توان از delegates در كارهاي عملي استفاده كرد؟

طرح يك مساله:
شخصي تقاضاي ثبت نام در يك مؤسسه ي آموزشي و همچنين تقاضاي كاريابي در يك شركت را داده است. هر كدام از اين نهادها روشي خاص خود را براي ارزيابي شخص دارند.

راه حل (با روشي شيء گرا):
شخص مشخصاتي همچون سن / جنس / ميزان تحصيلات قبلي / تجربيات كاري و مدارك مرتبط دارد.
مؤسسه ي آموزشي تعدادي از اين مشخصات را براي ارزيابي شخص استفاده مي كند و اين امر در مورد شركت ياد شده نيز صادق است.
شيء شركت و شيء آموزشگاه هر كدام توابع ارزيابي خاص خودشان را پياده سازي مي كنند.
شخص ، اينترفيسي واحدي را در اختيار شركت / آموزشگاه براي ارزيابي خود قرار مي دهد.

پياده سازي (با استفاده از سي شارپ):
ما delegate‌ايي را تعريف مي كنيم كه بيانگر اينترفيسي است كه به شركت و آموزشگاه اجازه ي چك كردن شخص را مي دهد.
سه كلاس school و company و person را تعريف مي نماييم.
كلاس test را براي آزمودن اين موارد ايجاد مي كنيم.

01 using System;
02 using System.Collections;

03 public delegate bool GetChecker(Person p);

// Person has his information with him as he
// applies for School and Company
04 public class Person
05 {
06 public string Name;
07 public int Age;
08 public bool Graduate;
09 public int YearsOfExp;
10 public bool Certified;

11 public Person(string name,
int age,
bool graduate,
int yearsOfExp,
bool certified)
12 {
13 Name=name;
14 Age=age;
15 Graduate=graduate;
16 YearsOfExp=yearsOfExp;
17 Certified=certified;
18 }
19 public bool CheckMe(GetChecker checker)
20 {
21 return(checker(this));
22 }
23 }

// A school, the person applied for higher studies
24 public class School
25 {
26 public static bool SchoolCheck(Person p)
27 {
28 return (p.Age>10 && p.Graduate);
29 }
30 }

// A Company, the person wants to work for
31 public class Company
32 {
33 public static bool CompanyCheck(Person p)
34 {
35 return (p.YearsOfExp>5 && p.Certified);
36 }
37 }

// A Test class, displays delegation in action
38 public class Test
39 {
40 public static void Main()
41 {
42 Person p1 = new Person("Jack",20,true,6,false);
43 Console.WriteLine("{0} School Check : {1}",
p1.Name,
p1.CheckMe(new GetChecker(School.SchoolCheck)));
44 Console.WriteLine("{0} Company Check : {1}",
p1.Name,
p1.CheckMe(new GetChecker(Company.CompanyCheck)));
45 }
46 }

LINE 03
Delegate مورد نياز را تعريف مي كند.

LINE 04-23
كلاس person را تعريف مي كند. اين كلاس تابعي پابليك را ارائه مي دهد كه آرگومان ورودي آن از نوع GetChecker مي باشد.

LINE 24-30
كلاس school را تعريف مي كند و سپس تابعي را كه delegate است ارائه مي دهد.

LINE 31-37
كلاس company را تعريف مي كند و سپس تابعي را كه delegate است ارائه مي دهد.

LINE 38-36
كلاس test را پياده سازي مي نمايد. سپس يك شيء شخص ساخته مي شود. در ادامه new GetChecker(School.SchoolCheck) و new GetChecker(Company.CompanyCheck) شيء ايي را ايجاد مي كند از نوع delegate مورد نياز و آنرا به تابع CheckMe مي فرستد. خروجي نتيجه ي ارزيابي اين شخص مي باشد.

اگر چك كردن اشخاص بيشتري نياز باشد به اين صورت عمل مي شود:

Person p1 = new Person("Jack",20,true,6,false);
Person p2 = new Person("Daniel",25,true,10,true);
GetChecker checker1= new GetChecker(School.SchoolCheck);
GetChecker checker2= new GetChecker(School.CompanyCheck);

Console.WriteLine("{0} School Check : {1}",
p1.Name,p1.CheckMe(checker1));
Console.WriteLine("{0} Company Check : {1}",
p1.Name,p1.CheckMe(checker2));
Console.WriteLine("{0} School Check : {1}",
p2.Name,p2.CheckMe(checker1));
Console.WriteLine("{0} Company Check : {1}",
p2.Name,p2.CheckMe(checker2));

مثال 3 :
Delegates در تعامل بين دات نت فريم ورك و سي شارپ چه نقشي دارد؟

طرح يك مساله:
نمايش دادن ميزان پيشرفت خواندن يك فايل هنگامي كه حجم فايل بسيار زياد است.

راه حل ( با استفاده از سي شارپ):
در مثال زير از كلاس FileReader براي خواندن يك فايل حجيم استفاده شده است. هنگاميكه برنامه مشغول خواندن فايل است 'Still reading.. را نمايش مي دهد و در پايان 'Finished reading..'. را عرضه مي كند.
براي اينكار از فضاي نام System.IO استفاده شده است. اين فضاي نام حاوي delegate ايي مهيا شده براي ما مي باشد. بدين ترتيب مي توانيم به دات نت فريم ورك بگوييم كه ما تابعي را تعريف كرده ايم كه او مي تواند آنرا فراخواني كند.
سؤال: چه نيازي وجود دارد تا دات نت فريم ورك تابع ما را فراخواني و اجرا كند؟ با استفاده از تابع ما كه دات نت فريم آنرا صدا خواهد زد در طول خواندن فايل به ما گفته مي شود كه بله! من هنوز مشغول خواندن هستم! به اين عمليات Callback نيز گفته مي شود. به اينكار پردازش asynchronous نيز مي گويند!

01 using System;
02 using System.IO;

03 public class FileReader{
04 private Stream sInput;
05 private byte[] arrByte;
06 private AsyncCallback callbackOnFinish;

07 public FileReader(){
08 arrByte=new byte[256];
09 callbackOnFinish = new AsyncCallback(this.readFinished);
10 }

11 public void readFinished(IAsyncResult result){

12 if(sInput.EndRead(result)>0){
13 sInput.BeginRead(arrByte,
0,
arrByte.Length,
callbackOnFinish,
null);
14 Console.WriteLine("Still reading..");
15 }
16 else Console.WriteLine("Finished reading..");
17 }

18 public void readFile(){
19 sInput = File.OpenRead(@"C:\big.dat");
20 sInput.BeginRead(arrByte,
0,
arrByte.Length,
callbackOnFinish,
null);
21 for(long i=0;i<=1000000000;i++){
// just to introduce some delay
22 }
23 }

24 public static void Main(){
25 FileReader asynctest=new FileReader();
26 asynctest.readFile();
27 }
28 }

LINE 02
فضاي نام System.IO را به برنامه ملحق مي كند. اين فضاي نام به صورت خودكار حاوي تعريف delegate زير مي باشد:

public delegate void AsyncCallback (IAsyncResult ar);

LINE 03-10
تعريف كلاس

LINE 06
شيء delegate را تعريف مي كند.

LINE 07-10
سازنده ي كلاس را پياده سازي مي كنند. در اينجا ما تصميم گرفته ايم كه بافري حاوي 256 بايت را در هر لحظه بخوانيم.

LINE 09
شيء delegate نمونه سازي شده است.

LINE 18-23
readFile را پياده سازي مي كند.

LINE 12-16
نحوه ي استفاده از شيء IAsyncResult را بيان مي كند.

LINE 12
sInput.EndRead(result) تعداد بايتهاي خوانده شده را بر مي گرداند. اين خواندن تاجايي كه تعداد بايتهاي خوانده شده صفر است ادامه پيدا مي كند و در اينجا 'Finished reading..' اعلام مي گردد.

http://www.irandevelopers.com :منبع

+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:44  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت نوزدهم

سربارگذاري عملگر ها (Operator OverLoading)

به تعريف مجدد راه و روش اجراي عملگر ها توسط ما ، سربارگذاري عملگرها گفته مي شود. فرض كنيد مي خواهيد عدد 2 را به يك مقدار datetime اضافه كنيد. خطاي زير حاصل خواهد شد:

CS0019: Operator '+' cannot be applied to operands of type 'System.DateTime' and 'int'


جالب بود اگر مي توانستيم عدد 2 را به datetime اضافه كنيم و نتيجه ي آن تعداد روزهاي مشخص بعلاوه ي دو مي بود. اينگونه توانايي ها را مي توان بوسيله ي operator overloading ايجاد كرد.

تنها عملگر هاي زير را مي توان overload كرد:

Unary Operators
+ - ! ~ ++ -- true false

Binary Operators
+ - * / % & | ^ << >> == != > < >= <=


نحوه ي انجام اينكار نيز در حالت كلي به صورت زير است:

return_datatype operator operator_to_be_overloaded (agruments)
{
}


به مثال زير توجه كنيد:

using System;
class MyDate
{
public DateTime tempDate;
public MyDate(int year,int month,int day)
{
tempDate=new DateTime(year,month,day);
}
public static DateTime operator + (MyDate D,int noOfDays)
{
return D.tempDate.AddDays(noOfDays);
}
public static DateTime operator + (int noOfDays,MyDate D)
{
return D.tempDate.AddDays(noOfDays);
}
}

class Test
{
static void Main()
{
MyDate MD=new MyDate(2001,7,16);
Console.WriteLine(MD + 10 );
}
}

output:
2001-07-26


در مثال فوق عملگر + دوبار overload شده است. يكبار توسط آن مي توان يك عدد صحيح را به يك تاريخ اضافه كرد و بار ديگر يك يك تاريخ را مي توان به عدد صحيح افزود.


موارد زير را هنگام سربارگذاري عملگرها به خاطر داشته باشيد:

1- تنها اپراتورهاي ذكر شده را مي توان overload كرد. اپراتورهايي مانند new,typeof, sizeof و غيره را نمي توان سربارگذاري نمود.
2- خروجي متدهاي بكار گرفته شده در سربارگذاري عملگر ها نمي تواند void باشد.
3- حداقل يكي از آرگومانهاي بكار گرفته شده در متدي كه براي overloading عملگرها بكار مي رود بايد از نوع كلاس حاوي متد باشد.
4- متدهاي مربوطه بايد به صورت public و static تعريف شوند.
5- هنگامي كه اپراتور < را سربارگذاري مي كنيد بايد جفت متناظر آن يعني > را هم سربارگذاري نماييد.
6- هنگاميكه براي مثال + را overload مي كنيد خودبخود =+ نيز overload شده است و نيازي به كدنويسي براي آن نيست.


يكي از موارد جالب بكار گيري سربارگذاري عملگرها در برنامه نويسي سه بعدي و ساختن كلاسي براي انجام عمليات ماتريسي و برداري مي باشد

+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:43  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت هجدهم

مقابله با خطاها در سي شارپ (Exception Handling in C#)

EXCEPTION يك خطاي زمان اجر است كه بدليل شرايطي غيرنرمال در برنامه ايجاد مي شود. در سي شارپ exeption كلاسي است در فضاي نام سيستم. شيء ايي از نوع exception بيانگر شرايطي است كه سبب رخ دادن خطا در كد شده است. سي شارپ از exception ها به صورتي بسيار شبيه به جاوا و سي پلاس پلاس استفاده مي نمايد.

دلايلي كه بايد در برنامه exception handling حتما صورت گيرد به شرح زير است:
- قابل صرفنظر كردن نيستند و اگر كدي اين موضوع را در نظر نگيرد با يك خطاي زمان اجرا خاتمه پيدا خواهد كرد.
- سبب مشخص شدن خطا در يك نقطه از برنامه شده و ما را به اصلاح آن سوق مي دهد.

بوسيله ي عبارات try...catch مي توان مديريت خطاها را انجام داد. كدي كه احتمال دارد خطايي در آن رخ دهد درون try قرار گرفته و سپس بوسيله ي يك يا چند قطعه ي catch مي توان آنرا مديريت كرد. و اگر از اين قطعات خطايابي استفاده نشود برنامه به صورتهاي زير متوقف خواهد شد :

class A {static void Main() {catch {}}}
TEMP.cs(3,5): error CS1003: Syntax error, 'try' expected

class A {static void Main() {finally {}}}
TEMP.cs(3,5): error CS1003: Syntax error, 'try' expected

class A {static void Main() {try {}}}
TEMP.cs(6,3): error CS1524: Expected catch or finally

بهتر است يك مثال ساده را در اين زمينه مرور كنيم:

int a, b = 0 ;
Console.WriteLine( "My program starts " ) ;
try
{
a = 10 / b;
}
catch ( Exception e )
{
Console.WriteLine ( e ) ;
}
Console.WriteLine ( "Remaining program" ) ;
The output of the program is:
My program starts
System.DivideByZeroException: Attempted to divide by zero.
at ConsoleApplication4.Class1.Main(String[] args) in
d:\dont delete\consoleapplication4\class1.cs:line 51
Remaining program

برنامه شروع به اجرا مي كند. سپس وارد بلوك و يا قطعه ي try مي گردد. اگر هيچ خطايي هنگام اجراي دستورات داخل آن رخ ندهد ، برنامه به خط آخر جهش خواهد كرد و كاري به قطعات catch ندارد.
اما در اينجا در اولين try عددي بر صفر تقسيم شده است بنابراين كنترل برنامه به بلوك catch منتقل مي شود و صرفا نوع خطاي رخ داده شده نوشته و نمايش داده مي شود. سپس برنامه به كار عادي خودش ادامه مي دهد.

تعدادي از كلاس هاي exception در سي شارپ كه از كلاس System.Exception ارث برده اند به شرح زير هستند :

• Exception Class - - Cause
• SystemException - A failed run-time check;used as a base class for other.
• AccessException - Failure to access a type member, such as a method or field.
• ArgumentException - An argument to a method was invalid.
• ArgumentNullException - A null argument was passed to a method that doesn't accept it.
• ArgumentOutOfRangeException - Argument value is out of range.
• ArithmeticException - Arithmetic over - or underflow has occurred.
• ArrayTypeMismatchException - Attempt to store the wrong type of object in an array.
• BadImageFormatException - Image is in the wrong format.
• CoreException - Base class for exceptions thrown by the runtime.
• DivideByZeroException - An attempt was made to divide by zero.
• FormatException - The format of an argument is wrong.
• IndexOutOfRangeException - An array index is out of bounds.
• InvalidCastExpression - An attempt was made to cast to an invalid class.
• InvalidOperationException - A method was called at an invalid time.
• MissingMemberException - An invalid version of a DLL was accessed.
• NotFiniteNumberException - A number is not valid.
• NotSupportedException - Indicates sthat a method is not implemented by a class.
• NullReferenceException - Attempt to use an unassigned reference.
• OutOfMemoryException - Not enough memory to continue execution.
• StackOverflowException - A stack has overflown.

در كد فوق صرفا عمومي ترين نوع از اين كلاس ها كه شامل تمامي اين موارد مي شود مورد استفاده قرار گرفت يعني :

catch ( Exception e )

اگر نيازي به خطايابي دقيقتر باشد مي توان از كلاس هاي فوق براي اهداف مورد نظر استفاده نمود.

مثالي ديگر: ( در اين مثال خطايابي دقيق تر با استفاده از كلاس هاي فوق و همچنين مفهوم finally نيز گنجانده شده است )

int a, b = 0 ;
Console.WriteLine( "My program starts" ) ;
try
{
a = 10 / b;
}
catch ( InvalidOperationException e )
{
Console.WriteLine ( e ) ;
}
catch ( DivideByZeroException e)
{
Console.WriteLine ( e ) ;
}
finally
{
Console.WriteLine ( "finally" ) ;
}
Console.WriteLine ( "Remaining program" ) ;
The output here is:
My program starts
System.DivideByZeroException: Attempted to divide by zero.
at ConsoleApplication4.Class1.Main(String[] args) in
d:\dont delete\consoleapplication4\class1.cs:line 51
finally
Remaining program

قسمت موجود در قطعه ي فاينالي همواره صرفنظر از قسمت هاي ديگر اجرا مي شود.

به مثال زير دقت كنيد :

int a, b = 0 ;
Console.WriteLine( "My program starts" )
try
{
a = 10 / b;
}
finally
{
Console.WriteLine ( "finally" ) ;
}
Console.WriteLine ( "Remaining program" ) ;
Here the output is
My program starts
Exception occurred: System.DivideByZeroException:
Attempted to divide by zero.at ConsoleApplication4.Class1.
Main(String[] args) in d:\dont delete\consoleapplication4
\class1.cs:line 51
finally

قسمت چاپ Remaining program اجرا نشده است.

عبارت throw :

اين عبارت سبب ايجاد يك خطا در برنامه مي شود.

مثال :

int a, b = 0 ;
Console.WriteLine( "My program starts" ) ;
try
{
a = 10 / b;
}
catch ( Exception e)
{
throw
}
finally
{
Console.WriteLine ( "finally" ) ;
}

در اين حالت قسمت فاينالي اجرا شده و برنامه بلافاصله خاتمه پيدا مي كند
 
+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:42  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت هفدهم

در كلاس CCommObj كه با آن آشنا شديم ، آرايه اي Private از نوع ICommObjEvents به نام m_arSinkColl وجود دارد. اين آرايه تمام اينترفيس هاي sink شده را ذخيره مي كند. واژه ي sink در اينجا به كلاسي گفته مي شود كه دريافت كننده ي رخدادها است. متد Advise تنها sink وارده به آنرا در يك آرايه ذخيره مي كند و سپس انديس آرايه را كه در اينجا cookie ناميده شده است بر مي گرداند. اين كوكي توسط كلاينتي كه ديگر نمي خواهد از آن آيتم هيچونه رخدادي را دريافت كند به سرور فرستاده مي شود و سپس سرور اين آيتم را از ليست خودش حذف خواهد كرد.

نحوه ي فراخواني متد advise توسط كلاينت نيز جالب است.

public void Init(CCommObj theSource)
{
m_Server = theSource;
theSource.Advise (this);
string strAdd = ("Hello");
m_Server.read (strAdd,10);
}

در اينجا تنها يك this بعنوان آرگومان به متد advice فرستاده شده است در حاليكه انتظار مي رفت آرگوماني از نوع ICommObjEvents به تابع فرستاده شود. دليل صحت اين عمل بدين صورت است كه كلاس ClientApp_A از اينترفيس ICommObjEvents ارث برده است و آنرا پياده سازي نموده است.
در ادامه ليست كامل برنامه ي نوشته شده را در حالت Console ملاحظه مي فرماييد.

namespace CSharpCenter
{

using System;

public interface ICommObjEvents
{
void OnDataSent();
void OnError();
}
public class CCommObj
{
private int m_nIndex;
public ICommObjEvents [] m_arSinkColl;
public CCommObj()
{
m_arSinkColl = new ICommObjEvents[10];
m_nIndex = 0;
}

public void Advise(ICommObjEvents theSink)
{

m_arSinkColl[m_nIndex] = theSink;
m_nIndex++;
}
public void SendData(string strData)
{
foreach ( ICommObjEvents theSink in m_arSinkColl)
{
if(theSink != null )
{
theSink.OnDataSent ();
}
}
}
}
class CClientApp_A:ICommObjEvents
{
public void OnDataSent()
{
Console.WriteLine("OnDataSent Client App A");
}
public void OnError()
{
Console.WriteLine("OnError");
}
public void Read()
{
string strAdd = ("Hello");
m_Server.SendData (strAdd);

}
private CCommObj m_Server;
public void Init(CCommObj theSource)
{
m_Server = theSource;
theSource.Advise (this);
}
}
class CClientApp_B:ICommObjEvents
{
public void OnDataSent()
{
Console.WriteLine("OnDataSent Client App B");
}
public void OnError()
{
Console.WriteLine("OnError");
}
private CCommObj m_Server;
public void Init(CCommObj theSource)
{
m_Server = theSource;
theSource.Advise (this);
}
}
class ConsoleApp
{
public static void Main()
{
CClientApp_A theClient = new CClientApp_A ();
CClientApp_B theClient2 = new CClientApp_B ();
CCommObj theComm = new CCommObj ();
theClient.Init (theComm);
theClient2.Init (theComm);
theClient.Read();

}
}

}

در متد Main برنامه ي فوق ، ما دو كلاينت تعريف كرده ايم و يك نمونه از CCommObj را. دو كلاينت instance هاي CCommObj را بعنوان آرگومان دريافت كرده اند. در هنگام فراخواني init توسط هر كلاينت متد advise فراخواني مي گردد. در خاتمه Read مربوط به كلاينت 1 فراخواني شده است كه سبب مي شود تا رخداد OnDataSend شيء CCommObj اجرا شود و به تمام كلاينت ها فرستاده شود.

هدف از اين مثال ارائه ي بعضي از جنبه هاي اينترفيس ها و نحوه ي استفاده از آنها بود. دو مطلب ديگر در مورد اينترفيس ها باقي مانده اند تا به پايان بحث مربوط به آنها برسيم:

چگونه مي توان متوجه شد كه يك شيء واقعا يك اينترفيس را پياده سازي كرده است؟
دو روش براي فهميدن اين موضوع وجود دارد:
- استفاده از كلمه ي كليدي is
- استفاده از كلمه ي كليدي as

اولين مثال زير از كلمه ي كليدي is استفاده مي كند :

CClientApp_C theClient3 = new CClientApp_C ();
if(theClient3 is ICommObjEvents)
Console.WriteLine ("theClient3 implements ICommObjEvents");
else
Console.WriteLine ("theClient3 doesnot implement ICommObjEvents");

كلمه ي كليدي is مقدار true را بر مي گرداند اگر اپراتور سمت چپ ، اينترفيس سمت راست را پياده سازي كرده باشد.

ICommObjEvents theClient5 = theClient3 as ICommObjEvents;
if(theClient5 != null )
Console.WriteLine ("Yes theClient implements interface");

else
Console.WriteLine ("NO,Yes theClient doesn't implements interface");

در مثال فوق اپراتور as در حال casting شيء theClient5 به ICommObjEvents مي باشد. چون CClientApp_C اينترفيس را پياده سازي نمي كند حاصل خط اول نال خواهد بود.

به صورت خلاصه :
يك اينترفيس قراردادي است كه به كلاينت گارانتي مي دهد يك كلاس خاص چگونه رفتار خواهد كرد. هنگاميكه كلاسي يك اينترفيس را پياده سازي مي كند به تمام كلاينت ها مي گويد كه : من تمام موارد ذكر شده در اينترفيس را ارائه و پياده سازي خواهم كرد. نمونه ي عملي استفاده از اينترفيس ها بحث dot net remoting است.
 
+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:40  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت شانزدهم

كلاس ها ي abstract
كلاس ها را همچنين مي توان به صورت abstract تعريف كرد. از اين نوع كلاس ها نمي توان instance ايي را ايجاد نمود. در اين كلاس هاي پايه ، صرفا تعريف متدها و خواص هايي عنوان گرديده و در آينده در كلاس هاي فرزند توسعه داده خواهند شد. براي مثال :

public abstract class Named
{
public abstract String Name {get; set;} // property
public abstract void PrintName(); // method
}
public class B : Named
{
private String name = "empty";
public override String Name
{
get{return name;}
set{name=value;}
}
public override void PrintName()
{
Console.WriteLine("Name is {0}", name);
}
}

والي كه شايد پيش بيايد اين است كه اگر interface ها صرفا تعريف توابع و خواص را مي توانند در خود جاي دهند پس چه دليلي براي بكار بردن آنها و طولاني كردن كار كد نويسي وجود دارد؟
كاربردهاي زيادي را مي توان براي اينترفيس ها برشمرد. اينترفيس يك رفتار را تعريف مي كند. فرض كنيد در حال توسعه ي برنامه ايي هستيد كه بر روي دو كامپيوتر مختلف بايد با هم در ارتباط مستقيم بوده و برهم كنش داشته باشند و هر برنامه از ماژولي به نام CCommObj communication object استفاده مي نمايد. يكي از متدهاي اين شيء ، SendData() مي باشد كه رشته اي را دريافت كرده و به برنامه ي ديگر مي فرستد. اين فراخواني از نوع asynchronous است زيرا ما نمي خواهيم اگر خطايي در شبكه رخ داد، برنامه براي هميشه منتظر باقي بماند. اما چگونه برنامه ي A كه تابع ذكر شده را فراخواني كرده است مي تواند تشخيص دهد كه پيغام به مقصد رسيده است يا خير و يا آيا خطايي در شبكه مانع رسيدن پيغام گشته است يا خير؟ جواب بدين صورت است كه CCommObj هنگام دريافت پيغام ، رخدادي را سبب خواهد شد و اگر خطايي رخ داده باشد خير. در اين حالت نياز به يك ماژول logging نيز احساس مي گردد تا خطاهاي رخ داده را ثبت نمايد. يك روش انجام آن اين است كه CCommObj پياده سازي اين امكان را نيز بعهده گرفته و اگر فردا نيز خواستيم ماژول ديگري را به برنامه اضافه كنيم هر روز بايد CCommObj را تغيير دهيم. تمام اين كارها را به سادگي مي توان در يك اينترفيس مدل كرد. روش آن نيز در ادامه بيان مي گردد:
در ابتدا يك اينترفيس ايجاد مي كنيم تا ليست تمام امكانات ممكن را "منتشر" كند:

interface ICommObjEvents
{
void OnDataSent();
void OnError();
}

شي ء CCommObj ما از اين توابع كه بعدا توسعه داده خواهند شد براي با خبر سازي كلاينت ها استفاده مي نمايد. تمام متدها در يك اينترفيس ذاتا پابليك هستند بنابراين نيازي به ذكر صريح اين مطلب نمي باشد و اگر اينكار را انجام دهيد كامپايلر خطاي زير را گوشزد خواهد كرد :

The modifier 'public' is not valid for this item

در ادامه كلاينت CClientApp_A را پياده سازي خواهيم كرد :

class CClientApp_A:ICommObjEvents
{
public void OnDataSent()
{
Console.WriteLine("OnDataSent");
}
public void OnError()
{
Console.WriteLine("OnError");
}
private CCommObj m_Server;
public void Init(CCommObj theSource)
{
m_Server = theSource;
theSource.Advise (this);
string strAdd = ("N450:1");
m_Server.read (strAdd,10);
}
}

در كد فوق كلاس CClientApp_A از ICommObjEvents ارث برده و تمام متدهاي اين اينترفيس را پياده سازي نموده است. هنگامي كه CCommObj تابع OnDataSent را فراخواني مي كند اين كلاينت پيغام را دريافت خواهد كرد. لازم به ذكر است كه كلاس كلاينت ما چون از يك اينترفيس ارث بري مي نمايد پس بايد تمام توابع و خواص كلاس پايه را پياده سازي كند در غير اينصورت هر چند برنامه كامپايل خواهد شد اما هنگامي كه شيء CCommObj هر كدام از توابع اين كلاس را فراخواني كد ، خطاي زمان اجرا رخ خواهد داد.
متد Init كلاس فوق آرگوماني را از نوع CCommObj دريافت نموده و در يك متغير private آنرا ذخيره مي نمايد. همچنين در اين متد ، متد Advise از كلاس CCommObj نيز فراخواني گشته است.

public class CCommObj
{
private int m_nIndex;
public ICommObjEvents [] m_arSinkColl;
public CCommObj()
{
m_arSinkColl = new ICommObjEvents[10];
m_nIndex = 0;
}
public int Advise(ICommObjEvents theSink)
{
m_arSinkColl[m_nIndex] = theSink;
int lCookie = m_nIndex;
m_nIndex++;
return lCookie
}
public void SendData(string strData)
{
foreach ( ICommObjEvents theSink in m_arSinkColl)
if(theSink != null )
theSink.OnDataSent ();
}
}
 
+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:38  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت پانزدهم

پلي مرفيسم (Polymorphism)

يكي ديگر از مفاهيم اوليه ي شيء گرايي پلي مرفيسم ( چند ريختي ) مي باشد. پلي مرفيسم به معناي توانايي استفاده كردن از فرم هاي مختلف يك نوع است بدون توجه به جزئيات آن .
براي مثال هنگاميكه سيگنال تلفني شما فرستاده مي شود ، از نوع تلفني كه در انتهاي خط موجود است خبري ندارد. تلفن انتهاي خط ، مي خواهد يكي از تلفن هاي عهد عتيق باشد و يا تلفني با آخرين امكانات روز .
شركت مخابرات (!) تنها از نوع پايه اي به نام phone خبر دارد و فرض مي كند كه هر instance از اين نوع مي داند كه چگونه صداي زنگ تلفن شما را به صدا در آورد. بنابراين شركت مخابرات از تلفن شما به صورت پلي مرف استفاده مي كند.
در عمل پلي مرفيسم هنگامي مفيد خواهد بود كه بخواهيم گروهي از اشياء را به يك آرايه نسبت دهيم و سپس متدهاي هر يك را فراخواني كنيم. الزاما اين اشياء از يك نوع نخواهند بود.

نحوه ي ايجاد متدهاي پلي مرفيك :
براي ايجاد متدي كه نياز است تا پلي مرفيسم را پشتيباني نمايد ، تنها كافي است آنرا از نوع virtual در كلاس پايه تعريف كنيم. مثال :
فرض كنيد تابع DrawWindow در كلاس Window تعريف شده است. براي ايجاد قابليت پلي مرفيسم در آن به صورت زير عمل مي شود :

public virtual void DrawWindow( )

در اين حالت هر كلاسي كه از Window مشتق شود ، مجاز است نگارش خاص خودش را از DrawWindow ارائه كند. در اين صورت در كلاسي كه از كلاس پايه ي ما ارث مي برد ، تنها كافي است كه كلمه ي كليدي override را قبل از نام تابع مذكور ذكر نماييم.

يك مثال كامل :

using System;

public class DrawingObject
{
public virtual void Draw()
{
Console.WriteLine("I'm just a generic drawing object.");
}
}
public class Line : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Line.");
}
}

public class Circle : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Circle.");
}
}

public class Square : DrawingObject
{
public override void Draw()
{
Console.WriteLine("I'm a Square.");
}
}
public class DrawDemo
{
public static int Main(string[] args)
{
DrawingObject[] dObj = new DrawingObject[4];

dObj[0] = new Line();
dObj[1] = new Circle();
dObj[2] = new Square();
dObj[3] = new DrawingObject();

foreach (DrawingObject drawObj in dObj)
{
drawObj.Draw();
}

return 0;
}
}

كلاس DrawingObject ، كلاسي پايه براي تمام كد ما كه از آن به ارث مي برد ، مي باشد. متد Draw در آن با كلمه ي كليدي virtual معرفي شده است. يعني تمام كلاس هاي فرزند اين كلاس والد مي توانند اين متد را override كنند ( تحريف كردن و يا تحت الشعاع قرار دادن هم ترجمه شده است! ).
در ادامه سه كلاس تعريف شده اند كه تمامي آنها از كلاس مبنا ارث مي برند و تابع Draw را تحريف كرده اند (!). با استفاده از كلمه ي كليدي override مي توان تابع مجازي كلاس مبنا را با تعريفي جديد در زمان اجراي برنامه ارائه داد. تحريف شدن تنها زماني رخ مي دهد كه كلاس ، توسط ريفرنس كلاس مبنا مورد ارجاع واقع شده باشد.
و در متد Main برنامه از اين كلاس ها در عمل استفاده گرديده است. در متد Main ، آرايه اي از نوع DrawingObject تعريف و مقدار دهي اوليه شده است تا بتواند 4 شيء از نوع اين كلاس را در خودش ذخيره كند.
بدليل رابطه ي ارث بري موجود مي توان آرايه ي dObj را با نوع هايي از كلاس هاي Line ، Circle و Square مقدار دهي كرد (همانند كدهاي بعدي متد Main ) . اگر ارث بري در اينجا وجود نمي داشت مي بايست به ازاي هر كلاس يك آرايه تعريف مي شد.
سپس از حلقه ي زيباي foreach براي حركت در بين اعضاي اين آرايه استفاده گرديده است. در اينجا هر شيء متد خاص خودش را در مورد Draw فراخواني مي كند و نتيجه را روي صفحه نمايش خواهد داد.
خروجي نهايي به صورت زير خواهد بود :

Output:
I'm a Line.
I'm a Circle.
I'm a Square.
I'm just a generic drawing object.
 
+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:37  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت چهاردهم

ارث بري (Inheritance) :

ارث بري يكي از مفاهيم اوليه ي برنامه نويسي شيء گرا مي باشد. با استفاده از آن استفاده مجدد از كد موجود به نحوي مؤثر ميسر مي گردد و صرفه جويي قابل توجهي را در زمان برنامه نويسي پديد مي آورد. به كد زير دقت كنيد :

using System;

public class ParentClass
{
public ParentClass()
{
Console.WriteLine("Parent Constructor.");
}
public void print()
{
Console.WriteLine("I'm a Parent Class.");
}
}

public class ChildClass : ParentClass
{
public ChildClass()
{
Console.WriteLine("Child Constructor.");
}
public static void Main()
{
ChildClass child = new ChildClass();
child.print();
}
}

Output:
Parent Constructor.
Child Constructor.
I'm a Parent Class.

كد فوق از دو كلاس استفاده مي كند. كلاس بالايي ParentClass و كلاس اصلي ChildClass مي باشد. كاري كه انجام شده است استفاده از كدهاي كلاس والد ParentClass در كلاس بچه (!) ChildClass مي باشد. براي اينكه ParentClass را بعنوان كلاس پايه براي ChildClass معرفي كنيم به صورت زير عمل شد :

public class ChildClass : ParentClass

كلاس پايه با استفاده از معرفي كولون ":" ، پس از كلاس مشتق شده تعريف مي شود. در سي شارپ تنها ارث بري يگانه پشتيباني مي شود. بنابراين تنها يك كلاس پايه را براي ارث بري مي توان تعريف كرد.

ChildClass دقيقا توانايي هاي ParentClass را دارا است. بنابراين مي توان گفت ChildClass همان ParentClass است. براي مثال در كد فوق ChildClass داراي متد print نمي باشد اما آنرا از كلاس ParentClass به ارث برده است و در متد Main برنامه از آن استفاده گرديده است.

هنگام ساختن يك شيء از كلاس مشتق شده (derived) ، ابتدا يك نمونه از كلاس والد خود بخود ساخته مي شود. اين مورد در خروجي كد فوق هنگامي كه متدهاي سازنده ها روي صفحه چاپ شده اند قابل مشاهده است.

تبادل اطلاعات بين كلاس والد و كلاس فرزند :

به مثال زير دقت كنيد :

using System;

public class Parent
{
string parentString;

public Parent()
{
Console.WriteLine("Parent Constructor.");
}

public Parent(string myString)
{
parentString = myString;
Console.WriteLine(parentString);
}

public void print()
{
Console.WriteLine("I'm a Parent Class.");
}
}

public class Child : Parent
{
public Child() : base("From Derived")
{
Console.WriteLine("Child Constructor.");
}

public void print()
{
base.print();
Console.WriteLine("I'm a Child Class.");
}

public static void Main()
{
Child child = new Child();
child.print();
((Parent)child).print();
}
}

Output:
From Derived
Child Constructor.
I'm a Parent Class.
I'm a Child Class.
I'm a Parent Class.

كلاس فرزند با كلاس والد در هنگام instantiation مي تواند تبادل اطلاعات كند. همانطور كه در مثال فوق بارز است با استفاده از كلمه ي كليدي base ، كلاس فرزند تابع سازنده ي كلاس والد را فراخواني كرده است. اولين خط خروجي بيانگر اين موضوع است.

گاهي از اوقات ما مي خواهيم تابعي را كه در كلاس والد تعريف شده است را در كلاس فرزند با تعريف ديگري و مخصوص به خودمان ارائه دهيم. در اينصورت تابع تعريف شده در كلاس فرزند ، تابع هم نام والد را مخفي خواهد كرد و ديگر آن تابع والد فراخواني نخواهد گرديد. در اين حالت تنها يك راه براي دسترسي به تابع اصلي والد وجود دارد و آن استفاده از base. مي باشد كه در كد فوق پياده سازي شده است.
با استفاده از base. مي توان به تمام اعضاي public و يا protected كلاس والد از درون كلاس فرزند دسترسي داشت.
راه ديگري كه براي اين منظور وجود دارد در آخرين خط كد فوق در متد Main پياده سازي شده است :

((Parent)child).print();

براي تبديل نوع هاي مختلف در سي شارپ مي توان از پرانتز و سپس ذكر نوع اصلي استفاده كرد به اين عمل casting و يا boxing هم مي گويند. در كد فوق درحقيقت child به نوعي از parent تبديل شده است. بنابراين مانند اين است كه يك نمونه از كلاس والد متد print همان كلاس را فراخواني مي كند.
 
+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:36  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت سيزدهم

با  استفاده از ايندكسرها مي توان با يك كلاس همانند آرايه ها رفتار كرد. به مثال زير توجه كنيد :

using System;

///
/// A simple indexer example.
///

class IntIndexer
{
private string[] myData;

public IntIndexer(int size)
{
myData = new string[size];

for (int i=0; i < size; i++)
{
myData[i] = "empty";
}
}

public string this[int pos]
{
get
{
return myData[pos];
}
set
{
myData[pos] = value;
}
}

static void Main(string[] args)
{
int size = 10;

IntIndexer myInd = new IntIndexer(size);

myInd[9] = "Some Value";
myInd[3] = "Another Value";
myInd[5] = "Any Value";

Console.WriteLine("\nIndexer Output\n");

for (int i=0; i < size; i++)
{
Console.WriteLine("myInd[{0}]: {1}", i, myInd[i]);
}
}
}

در مثال فوق نحوه ي تعريف و استفاده از ايندكسرها را مي توان مشاهده كرد. كلاس IntIndexer حاوي آرايه اي به نام myData مي باشد. بدليل private بودن آن در خارج از كلاس قابل دسترسي نيست. اين آرايه در سازنده ي كلاس (متد IntIndexer) با كلمه ي empty مقدار دهي اوليه شده است.
عضو بعدي كلاس Indexer مي باشد و با كلمه ي كليدي this و براكتها مشخص شده ست (this[int pos]). همانطور كه ملاحظه مي فرماييد نحوه ي تعريف ايندكسرها شبيه به تعريف خواص مي باشد.

this [argument list]
{
get
{
// Get codes goes here
}
set
{
// Set codes goes here
}
}

خروجي مثال فوق به صورت زير است :

myInd[0]: empty
myInd[1]: empty
myInd[2]: empty
myInd[3]: Another Value
myInd[4]: empty
myInd[5]: Any Value
myInd[6]: empty
myInd[7]: empty
myInd[8]: empty
myInd[9]: Some Value

استفاده از اعداد صحيح روشي است متداول براي دسترسي به اعضاي آرايه ها در بسياري از زبانها اما ايندكسرها در سي شارپ فراتر از اين مي رود. ايندكسرها را مي توان با پارامترهاي متعددي تعريف كرد و هر پارامتر با نوعي مختلف (دقيقا همانند پارامترهاي ورودي متدها). البته محدوديتي كه اينجا وجود دارد در مورد نوع پارامتر ها است كه تنها مي تواند integers, enums, and strings باشد . بعلاوه قابليت Overloading ايندكسرها نيز وجود دارد. به همين جهت به آنها آرايه هاي هوشمند هم گفته مي شود (smart arrays) .مثال :

using System;

///
/// Implements overloaded indexers.
///

class OvrIndexer
{
private string[] myData;
private int arrSize;

public OvrIndexer(int size)
{
arrSize = size;
myData = new string[size];

for (int i=0; i < size; i++)
{
myData[i] = "empty";
}
}

public string this[int pos]
{
get
{
return myData[pos];
}
set
{
myData[pos] = value;
}
}

public string this[string data]
{
get
{
int count = 0;

for (int i=0; i < arrSize; i++)
{
if (myData[i] == data)
{
count++;
}
}
return count.ToString();
}
set
{
for (int i=0; i < arrSize; i++)
{
if (myData[i] == data)
{
myData[i] = value;
}
}
}
}

static void Main(string[] args)
{
int size = 10;
OvrIndexer myInd = new OvrIndexer(size);

myInd[9] = "Some Value";
myInd[3] = "Another Value";
myInd[5] = "Any Value";

myInd["empty"] = "no value";

Console.WriteLine("\nIndexer Output\n");

for (int i=0; i < size; i++)
{
Console.WriteLine("myInd[{0}]: {1}", i, myInd[i]);
}

Console.WriteLine("\nNumber of \"no value\" entries: {0}", myInd["no value"]);
}
}

در مثال فوق اولين ايندكسر با يك پارامتر از نوع اعداد صحيح تعريف شده است و در ايندكسر دوم از نوع رشته.
خروجي برنامه ي فوق به صورت زير است :

myInd[0]: no value
myInd[1]: no value
myInd[2]: no value
myInd[3]: Another Value
myInd[4]: no value
myInd[5]: Any Value
myInd[6]: no value
myInd[7]: no value
myInd[8]: no value
myInd[9]: Some Value

Number of "no value" entries: 7

نكته :
1- امضاي (ليست پارامترهاي) ايندكسر ها در يك كلاس بايد منحصر بفرد باشد .
2- تعريف يك ايندكسر به صورت استاتيك مجاز نيست.

در صورت نياز به ايندكسرهايي با پارمترهاي ورودي متعدد مي توان به صورت زير عمل كرد :

public object this[int param1, ..., int paramN]
{
get
{
// process and return some class data
}
set
{
// process and assign some class data
}
}

يك مثال ديگر :

using System;

class IndexExample
{
string Message;

public static void Main()
{
IndexExample obj=new IndexExample("Welcome");

/* This will access the String variable Message
using array like notation
*/
for(int i=0;i < obj.Length;i++)
{
Console.WriteLine(obj[i]);
}
obj[obj.Length-1]="e to C#";

Console.WriteLine(obj.Message);

}

public IndexExample(string s)
{
Message=s;
}

public string this[int i]
{
get
{
if(i >= 0 && i < Message.Length)
{
return Message.Substring(i,1);
}
else
{
return "";
}
}
set
{
if(i >= 0 && i < Message.Length)
{
Message=Message.Substring(0,i) + value + Message.Substring(i+1);
}
}
}

public int Length
{
get
{
if(Message!=null)
{
return Message.Length;
}
else
return 0;
}
}
}


+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:35  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت دوازدهم

كلاس ها در سي شارپ :

تا بحال در حد كاربرد ، با كلاس ها آشنا شده ايم . اما در اين قسمت مي خواهيم نگاهي دقيق تر به كلاس ها بياندازيم.

هر كدي در سي شارپ قسمتي از يك كلاس مي باشد و تركيب تمام خواص و متدهاي موجود در يك كلاس يك نوع داده ي جديد تعريف شده از طرف ما را پديد مي آورد. هر متغيري كه از كلاس ساخته شود ، شيء ناميده مي شود و يك كپي منحصر به فرد است. براي مثال برنامه ي زير را درنظر بگيريد :

using System;

class Data
{
public int x;
}
class App
{
public static void Main()
{
Data d1 = new Data();
d1.x = 1;
Data d2 = new Data();
d2.x = 2;
Console.WriteLine("d1.x = {0}", d1.x);
Console.WriteLine("d2.x = {0}", d2.x);
}
}

در اينجا كلاس Data تعريف شده است و داراي يك عضو به نام x مي باشد. به اين نوع داده در كلاس فيلد گفته مي شود و هنگاميكه به صورت public معرفي مي شود يعني خارج از كلاس نيز قابل دسترسي است. در كد بالا دو متغير از كلاس تعريف و مقدار دهي اوليه شده اند. خروجي برنامه به صورت زير است :

d1.x = 1
d2.x = 2

دليل اين خروجي آن است كه هر instance (نمونه) از كلاس منحصر بفرد است و در اينجا نمي توان انتظار داشت كه هر دو خروجي يكي شوند.

براي مقدار دهي اوليه متغيرهايي كه به صورت فيلد تعريف مي شوند ، بهتر است مقدار دهي آنها را در سازنده ي كلاس (constructor) انجام دهيم.

class Data
{
public int x;
public Data(){x = 99;}
}

همانطور كه پيشتر نيز ذكر شد ، متدي كه هم نام كلاس است ، سازنده نام مي گيرد. يك كلاس مي تواند بيش از يك سازنده داشته باشد. براي مثال :

class Data
{
public int x;
private Data(){}
public Data(int y){x = y;}
public Data(int y, int z){x = y + z;}
}

از آنجائيكه كه سازنده ي بدون پارامتر ذكر شده در كد فوق private تعريف شده است بنابراين خارج از كلاس ديگر قابل دسترسي نمي باشد . بنابراين كدي خارج از كلاس ، تنها مي تواند از دو سازنده ي ديگر استفاده كند. براي مثال تعريف دو متغير جديد از اين كلاس به صورت زير مي باشد :

Data d1 = new Data(44);
Data d2 = new Data(22, 33);

سي شارپ به شما اجازه مي دهد تا سازنده ها را در يك كلاس توسط كلمه ي كليدي this نيز فراخواني كنيد يعني بجاي ذكر نام متد سازنده از كلمه ي this استفاده شود ( در خود كلاس ) .

اگر مي خواهيد متغيري را بين نمونه (instance) هاي مختلف يك كلاس به اشتراك بگذاريد كلمه ي كليدي static وارد صحنه مي شود. به مثال زير توجه كنيد :

using System;

class Counted
{
public static int count = 0;
public Counted()
{
count++;
}
public int GetInstanceCount()
{
return count;
}
}
class App
{
public static void Main()
{
Counted d1 = new Counted();
Console.WriteLine("current total {0}", d1.GetInstanceCount());
Counted d2 = new Counted();
Console.WriteLine("current total {0}", d2.GetInstanceCount());
Console.WriteLine("total {0}", Counted.count);
}
}

بايد خاطر نشان كرد كه متغيرهاي استاتيك توسط نمونه هاي كلاس قابل دستيابي نيستند و فقط درون كلاس به شكل زير مي توان از آْنها استفاده كرد :

.

در مثال فوق دو نمونه از كلاس Counted تعريف شده است. با هر بار فراخواني كلاس ، خودبخود سازنده اجرا شده و يك عدد به اين شمارشگر استاتيك اضافه مي شود. همانطور كه ذكر شد، براي اينكه بتوان به اين متغير استاتيك در خارج از كد دسترسي پيدا كرد يك متد غير استاتيك تعريف شده است.

در مثال فوق تابع GetInstanceCount تنها يك عدد را بر مي گرداند. در برنامه نويسي شيء گرا مرسوم است كه در اين حالت به جاي توابع از خواص استفاده شود كه به اندازه ي كافي در مورد آنها در قسمت هاي قبل توضيح داده شد. در اين صورت تعريف فوق به صورت زير در مي آيد :

class Counted
{
public static int x = 0;
public Counted()
{
x++;
}
public int InstanceCount // property
{
get{return x;}
}
}

و در اين صورت قسمت بعدي كد به صورت زير اصلاح مي شود (فراخواني خواص ، بدون ذكر پرانتزها بعد از نام آنها صورت مي گيرد):

Counted d1 = new Counted();
Console.WriteLine("current total {0}", d1.InstanceCount);
Counted d2 = new Counted();
Console.WriteLine("current total {0}", d2.InstanceCount);

اگر يك خاصيت هم خواندني و هم نوشتني باشد به صورت زير تعريف مي شود :

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

فيلدهاي پابليك را مي توان خواند و يا تغيير داد. اگر لازم باشد تا كاربر نتواند آنها را تغيير دهد مي توان از كلمه ي كليدي readonly قبل از تعريف آنها استفاده كرد. مثال :

class Data
{
public readonly int x = 42;
}

بحث كلاس ها ادامه دارد...

+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:34  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت يازدهم

از اين قسمت به بعد مي خواهيم نگاهي دقيق تر به بحث شيء گرايي در سي شارپ بياندازيم؛ همانند فضاهاي نام ، كلاس ها ، ارث بري ، پلي مرفيسم و غيره.

در قسمت هاي قبل آشنايي مختصري با فضاهاي نام پيدا كرديم. در ادامه جزئيات بيشتري را در مورد آن بررسي خواهيم كرد.
فضاهاي نام (namespaces) براي اداره كردن و نظم بخشيدن به كدها ارائه شده اند. همچنين از امكان تشابه اسمي در بين قسمت هاي مختلف برنامه نيز جلوگيري مي كنند. استفاده از آنها عادت پسنديده اي است هنگاميكه قصد داريم از كد نوشته شده بارها و بارها استفاده كنيم.

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex24 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

// Namespace Declaration
using System;

namespace ex24
{
namespace tutorial
{
// Program start class
class NamespaceCSS
{
// Main begins program execution.
public static void Main()
{
// Write to console
Console.WriteLine("This is the new Namespace.");
}
}
}

}

توضيحاتي در مورد كد فوق :
يكي از روش هاي مناسب براي معرفي فضاهاي نام ، ارائه ي آنها به صورت سلسله مراتبي مي باشد. قسمت هاي عمومي تر در بالا و قسمت هاي اختصاصي تر در فصاهاي نام داخلي تر قرار داده مي شوند. اين روش به معرفي فضاهاي نام تو در تو منتهي مي شود (nested namespaces) ، همانند مثال بالا.

كد فوق را به صورت زير با استفاده از عملگر دات (.) مي توان خلاصه نويسي كرد و نتيجه با قبل تفاوتي ندارد:

// Namespace Declaration
using System;

namespace ex24.tutorial
{
// Program start class
class NamespaceCSS
{
// Main begins program execution.
public static void Main()
{
// Write to console
Console.WriteLine("This is the new Namespace.");
}
}
}

طريقه ي فراخواني اعضاي فضاهاي نام :

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex25 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

// Namespace Declaration
using System;

namespace ex25
{
// nested namespace
namespace tutorial
{
class myExample1
{
public static void myPrint1()
{
Console.WriteLine("calling another namespace member1.");
}
}
}

// Program start class
class NamespaceCalling
{
// Main begins program execution.
public static void Main()
{
// Write to console
tutorial.myExample1.myPrint1();
tutorial.myExample2.myPrint2();
}
}
}

// same namespace as nested namespace above
namespace ex25.tutorial
{
class myExample2
{
public static void myPrint2()
{
Console.WriteLine("calling another namespace member2.");
}
}
}

توضيحاتي در مورد كد فوق :
در كد فوق نحوه ي استفاده از اعضاي تعريف شده در فضاهاي نام را مي توان مشاهده كرد. نحوه ي استفاده از آنها همانطور كه در قسمت هاي قبل نيز گفته شد به صورت زير است :

ProjectName.NameSpace.ClassName.MemberName

براي مثال در فصاي نام tutorial كلاس myExample1 قرار دارد و داخل آن متد myPrint1 تعريف شده است. پس نحوه ي دسترسي به متد آن به صورت زير است :

tutorial.myExample1.myPrint1();

كلاس هاي myExample1 و myExample2 هر دو به يك فضاي نام (ex25.tutorial) تعلق دارند ، هر چند جدا از هم نوشته شده اند. حتي آنها را با حفظ سلسله مراتب خودشان مي توان در فايلهاي جداگانه اي نيز نوشت.

استفاده از using :

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex26 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

// Namespace Declaration
using System;
using ex26.tutorial;

// Program start class
class UsingDirective
{
// Main begins program execution.
public static void Main()
{
// Call namespace member
myExample.myPrint();
}
}

// C# Namespace
namespace ex26.tutorial
{
class myExample
{
public static void myPrint()
{
Console.WriteLine("Example of using a using directive.");
}
}
}

توضيحاتي در مورد كد فوق :

همانند مثال بالا ، براي خلاصه نويسي مي توان از كلمه ي using به همراه نام namespace مورد نظر استفاده كرد. براي مثال اگر متد WriteLine را بخواهيم كامل بنويسيم به صورت زير است :

System.Console.WriteLine(...);

اما با قيد كردن و الحاق كردن فضاي نام آن ، ديگر نيازي به ذكر System در ابتداي آن نيست.

نكته :

باز هم مي توان خلاصه نويسي بيشتري را ارائه داد

using csTut = ex26.tutorial.myExample; // alias

در اين صورت تنها كافي است متد كلاس تعريف شده در آنرا به صورت زير فراخواني كنيم :

csTut.myPrint();
+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:33  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت دهم

Jagged arrays

Jagged arrays آرايه اي از آرايه ها است و همانطور كه ذكر شد لزومي ندارد كه هر رديف آن با رديف بعدي هم طول باشد . هنگام تعريف اين نوع آرايه شما تعداد رديف ها را مشخص مي نماييد. هر رديف يك آرايه را نگهداري مي كند. در اينجا هر آرايه بايد تعريف شود. روش تعريف Jagged array به صورت زير است
type [] []...

در اينجا تعداد براكت ها بيانگر ابعاد آرايه مي باشد. براي مثال آرايه ي زير دو بعدي است :

int [] [] myJaggedArray;

و براي مثال براي دسترسي به پنجمين عنصر آرايه ي سوم به صورت زير عمل مي شود :

myJaggedArray[2][4]

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex21 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

using System;

namespace ex21
{
class Class1
{
[STAThread]
static void Main(string[] args)
{

const int rows = 4;
// declare the jagged array as 4 rows high
int[][] jaggedArray = new int[rows][];
// the first row has 5 elements
jaggedArray[0] = new int[5];
// a row with 2 elements
jaggedArray[1] = new int[2];
// a row with 3 elements
jaggedArray[2] = new int[3];
// the last row has 5 elements
jaggedArray[3] = new int[5];
// Fill some (but not all) elements of the rows
jaggedArray[0][3] = 15;
jaggedArray[1][1] = 12;
jaggedArray[2][1] = 9;
jaggedArray[2][2] = 99;
jaggedArray[3][0] = 10;
jaggedArray[3][1] = 11;
jaggedArray[3][2] = 12;
jaggedArray[3][3] = 13;
jaggedArray[3][4] = 14;
for (int i = 0;i < 5; i++)
{
Console.WriteLine("jaggedArray[0][{0}] = {1}",
i,jaggedArray[0][i]);
}
for (int i = 0;i < 2; i++)
{
Console.WriteLine("jaggedArray[1][{0}] = {1}",
i,jaggedArray[1][i]);
}
for (int i = 0;i < 3; i++)
{
Console.WriteLine("jaggedArray[2][{0}] = {1}",
i,jaggedArray[2][i]);
}
for (int i = 0;i < 5; i++)
{
Console.WriteLine("jaggedArray[3][{0}] = {1}",
i,jaggedArray[3][i]);
}

Console.ReadLine();

}
}
}

توضيحاتي در مورد كد فوق :

هنگام كار با آرايه هاي rectangular براي درسترسي به اعضا به صورت زير عمل مي شد :

rectangularArrayrectangularArray[i,j]

اما در اينجا بدين صورت است :

jaggedArray[3][i]

استفاده از System.Array :

دات نت فريم ورك كلاسي را معرفي كرده است به نام Array. توسط اين كلاس كار با آرايه ها و اعمال روي آنها براي مثال سورت كردن و غيره به شدت ساده مي شود .


مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex22 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

using System;

namespace ex22
{
class Class1
{
public static void PrintMyArray(object[] theArray)
{
foreach (object obj in theArray)
{
Console.WriteLine("Value: {0}", obj);
}
Console.WriteLine("\n");
}

[STAThread]
static void Main(string[] args)
{
String[] myArray = {
"Who", "is", "John", "Galt"
};
PrintMyArray(myArray);
Array.Reverse(myArray);
PrintMyArray(myArray);
String[] myOtherArray = {
"We", "Hold", "These", "Truths",
"To", "Be", "Self", "Evident" };

PrintMyArray(myOtherArray);
Array.Sort(myOtherArray);
PrintMyArray(myOtherArray);

Console.ReadLine() ;

}
}
}

توضيحاتي در مورد كد فوق :
از دو متد Sort و Reverse در اينجا براي سورت كردن و نمايش آرايه به ترتيب معكوس (از انتها به ابتدا) استفاده گرديده است.

تعريف آرايه هاي ديناميك در سي شارپ :

يكي از مشكلاتي كه با آرايه هاي معمول وجود دارد اين است كه قبل از هر كاري بايد طول آْنها را مشخص كرد. گاهي از اوقات ما دقيقا نمي دانيم برنامه چه تعداد عضو را دريافت مي كند تا آرايه اي از پيش تعريف شده با همان تعداد عضو ايجاد كنيم. براي حل اين مشكل از كلاس ArrayList تعريف شده در دات نت فريم ورك مي توان استفاده كرد.

هنگام استفاده از ArrayList نيازي به دانستن تعداد اعضايي كه بايد اضافه شوند نمي باشد و با استفاده از متد Add آن به سادگي مي توان اعضاء را به آن اضافه نمود . تعدادي از خواص و متدهاي اين كلاس به صورت زير هستند :

Adapter , FixedSize , ReadOnly , Repeat , Synchronized , Capacity,Count , IsFixedSize , IsReadOnly , IsSynchronized , Item , SyncRoot , Add , AddRange , BinarySearch , Clear , Clone , Contains , CopyTo , GetEnumerator , GetRange , IndexOf , Insert , InsertRange , LastIndexOf , Remove , RemoveAt , RemoveRange , Reverse , SetRange , Sort , ToArray , TrimToSize

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex23 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

using System;
using System.Collections;

namespace ex23
{
// a simple class to store in the array
public class Employee
{
public Employee(int empID)
{
this.empID = empID;
}
public override string ToString( )
{
return empID.ToString( );
}
public int EmpID
{
get
{
return empID;
}
set
{
empID = value;
}
}
private int empID;
}

class Class1
{
[STAThread]
static void Main(string[] args)
{

ArrayList empArray = new ArrayList( );
ArrayList intArray = new ArrayList( );
// populate the array
for (int i = 0;i<5;i++)
{
empArray.Add(new Employee(i+100));
intArray.Add(i*5);
}
// print all the contents
for (int i = 0;i {
Console.Write("{0} ", intArray[i].ToString( ));
}
Console.WriteLine("\n");
// print all the contents of the button array
for (int i = 0;i {
Console.Write("{0} ", empArray[i].ToString( ));
}
Console.WriteLine("\n");
Console.WriteLine("empArray.Capacity: {0}",
empArray.Capacity);

Console.ReadLine();

}
}
}

توضيحاتي در مورد كد فوق :

1- با كلمه ي كليدي override در قسمت هاي بعدي آشنا خواهيم شد.
2- براي استفاده از ArrayList لازم بود تا فضاي نامي را كه اين كلاس در آن تعريف شده است ، به برنامه اضافه كرد.
3- در مثال فوق نحوه ي تعريف دو كلاس را در يك فضاي نام مشاهده مي نماييد.
4- نحوه ي تعريف و مقدار دهي ArrayList و همچنين استفاده از خواص آن در مثال فوق بررسي شده است

+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:31  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت نهم

مبحث overloading :

گاهي از اوقات لازم است تا نگارش هاي مختلفي از يك تابع داشته باشيم. براي مثال تعريف سه تابع با يك نام اما با آرگومانهاي مختلف. به اين نوع توابع و يا متدها اصطلاحا Overloaded Methods مي گويند . ( فكر كنم آنرا سربارگذاري توابع ترجمه كرده اند! ) براي مثال :

void myMethod(int p1);
void myMethod(int p1, int p2);
void myMethod(int p1, string s1);

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex18 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

using System;

namespace ex18
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
writeIT();

writeIT(12);

Console.ReadLine();
}

public static void writeIT()
{
Console.WriteLine(" writeIT() Ver." );
}

public static void writeIT(int intI)
{
Console.WriteLine(" writeIT(intI) Ver. = " + intI );
}


}
}

توضيحاتي در مورد كد فوق :

1- نحوه ي تعريف دو تابع با يك نام را ملاحظه مي نماييد. اينكار در زبان سي ممنوع است!
2- كامپايلر به صورت هوشمند بر اساس نوع و تعداد آرگومانهاي ورودي ، ورژن مناسب را انتخاب و اجرا مي كند.

نمونه ي ضعيفي از اين بحث در وي بي 6 به صورت تعريف توابعي با پارامترهاي Optional وجود داشت .

مباحث تكميلي آرايه ها (آرايه هاي چند بعدي):

آرايه هاي معمولي (يك بعدي) را مي توان يك رديف با تعدادي خانه خالي آماده ي پر شدن در نظر گرفت. آرايه ي دوبعدي را مي توان مانند يك جدول تشكليل شده از رديف ها و ستون ها در نظر گرفت و الي آخر...
سي شارپ دو نوع آرايه ي چند بعدي را پشتيباني مي كند : rectangular and jagged
در يك آرايه ي rectangular هر رديف ، طولش با رديف بعدي يكي است. آرايه ي jagged در حقيقت آرايه ايي از آرايه ها است ، بنابراين هر كدام از آنها مي تواند طول مختلفي داشته باشد.

تعريف يك آرايه ي دوبعدي به صورت زير است :

type [,] array-name

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex19 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

using System;

namespace ex19
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
const int rows = 4;
const int columns = 3;
// declare a 4x3 integer array
int[,] rectangularArray = new int[rows, columns];
// populate the array
for (int i = 0;i < rows;i++)
{
for (int j = 0;j {
rectangularArray[i,j] = i+j;
}
}
// report the contents of the array
for (int i = 0;i < rows;i++)
{
for (int j = 0;j {
Console.WriteLine("rectangularArray[{0},{1}] = {2}",
i,j,rectangularArray[i,j]);
}
}

Console.ReadLine();
}
}
}

توضيحاتي در مورد كد فوق :
1- نحوه ي تعريف ، مقدار دهي اوليه و استفاده از آرايه هاي دو بعدي را در مثال فوق ملاحظه مي نماييد.
2- در يك آرايه ي دوبعدي محل قرار گيري رديف ها و ستون ها براي مثال به صورت زير است :

new int[rows, columns]-

استفاده از آرايه هاي چند بعدي :

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex20 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

using System;

namespace ex20
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
const int rows = 4;
const int columns = 3;
// imply a 4x3 array
int[,] rectangularArray =
{
{0,1,2},
{3,4,5},
{6,7,8},
{9,10,11}
};
for (int i = 0;i < rows;i++)
{
for (int j = 0;j {
Console.WriteLine("rectangularArray[{0},{1}] = {2}",
i,j,rectangularArray[i,j]);
}
}
}
}
}

توضيحاتي در مورد كد فوق :
1- در حقيقت مثال فوق تعريف آرايه ايي از آرايه ها بود.
2- چون مقدار دهي اوليه به صورت واضحي انجام شده نيازي به ذكر ابعاد آرايه به صورت صحيح وجود نداشت

+ نوشته شده در  شنبه بیست و چهارم تیر 1385ساعت 16:30  توسط DevilHell  | 

Cracking Magazine

دانلود کنید :

http://www.maghalat.persiangig.com/Cracking%20magazin/Cracking%20Magazine.zip

روی RUN-LEARNING کلیک کنید . . .

+ نوشته شده در  جمعه بیست و سوم تیر 1385ساعت 18:28  توسط DevilHell  | 

Kaspersky Internet Security 2006 6.0.0.299

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

برخی از ویژگی های این نرم افزار عبارتند از:
- محافظت در مقابل تمامی حملات اینترنتی
- دیواره آتش شخصی
- کنترل تمامی اطلاعات، ایمیل ها، اطلاعات مبادله شده به صورت بلادرنگ
- محافظت در مقابل انواع وروس ها، تروجان ها و کرم های اینترنتی
- محافظت در برابر انواع برنامه های مخرب
- محافظت در مقابل اسپم (نامه های ناخواسته)
- جلوگیری از ظاهر شدن پنجره های تبلیغاتی مزاحم
- برگرداندن تغییرات ایجاد شده توسط برنامه های مخرب
- به روز رسانی اتوماتیک
- و ..
.
_______
 
 
 
 
 
+ نوشته شده در  جمعه بیست و سوم تیر 1385ساعت 17:20  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت هشتم

چگونه از يك تابع بيش از يك خروجي دريافت كنيم.

ظاهرا به نظر مي رسد كه توابع فقط مي توانند يك return داشته باشند و بلافاصله پس از فراخواني return كار تابع پايان يافته است. در سي شارپ دو كلمه ي كليدي به نام هاي ref و out اضافه شده اند كه اين امر را ساده تر مي كنند.

استفاده از كلمه ي كليدي out :

از out در تعريف تابع قبل از معرفي نوع آرگومان ورودي استفاده مي كنيم . در اين حالت بجاي اينكه به اين آرگومان ، آرگومان ورودي بگوييم ، مي توان آنرا آرگومان خروجي ناميد. تا يك مثال را در اين زمينه با هم مرور نكنيم اين مورد مفهوم نخواهد بود :

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex15 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

using System;

namespace ex15
{
class Class1
{

public static int TestOut(out char i)
{
i = 'b';
return -1;
}

[STAThread]
static void Main(string[] args)
{
char i; // variable need not be initialized
Console.WriteLine(TestOut(out i));
Console.WriteLine(i);
Console.ReadLine();

}
}
}

توضيحاتي در مورد كد فوق :
1- در تابع TestOut آرگومان i از با كلمه ي كليدي out مشخص شده است. يعني اينكه درون تابع هر گونه تغييري روي i انجام شود ، خارج از تابع قابل دسترسي است.
2- توابعي كه داراي آرگومانهايي تعريف شده با كلمه ي كليدي out هستند نيز مي توانند از return هم استفاده كنند. همانند مثال فوق.

استفاده از كلمه ي كليدي ref :

اين كلمه ي كليدي نيز دقيقا همانند out عمل مي كند و نحوه ي تعريف و استفاده از آن نيز مشابه است با اين تفاوت كه آرگوماني كه به اين نوع توابع فرستاده مي شود بايد مقدار دهي اوليه شده باشد.

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex16 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

using System;

namespace ex16
{
class Class1
{
public static void FillArray(ref int[] arr)
{
// Create the array on demand:
if (arr == null)
arr = new int[10];
// Otherwise fill the array:
arr[0] = 123;
arr[4] = 1024;
}

[STAThread]
static void Main(string[] args)
{
// Initialize the array:
int[] myArray = {1,2,3,4,5};

// Pass the array using ref:
FillArray(ref myArray);

// Display the updated array:
Console.WriteLine("Array elements are:");
for (int i = 0; i < myArray.Length; i++)
Console.WriteLine(myArray[i]);

Console.ReadLine();
}
}
}

توضيحاتي در مورد كد فوق :
1- همانطور كه ملاحظه مي كنيد در اينجا هنگام استفاده از تابع FillArray بايد آرگوماني را كه مي خواهيم به آن پاس كنيم مقدار دهي اوليه كنيم.
2- پس مي توان نتيجه گرفت آرگومانهايي كه با out تعريف مي شوند به صورت خالص خروجي هستند و نيازي به مقدار دهي اوليه هنگام استفاده از آنها وجود ندارد. از ref هنگامي استفاده مي كنيم كه بخواهيم روي متغير موجود و مقدار دهي شده ي خارج از تابع ، درون تابع عملياتي صورت گيرد و سپس همان متغير دستكاري شده ، عودت داده شود.

تعريف تابعي با تعداد آرگومانهاي نامعلوم :

گاهي از اوقات نياز است تا تابعي تعريف كنيم كه تعداد آرگومانهاي آن متغير باشند .براي اين منظور از كلمه ي كليدي params استفاده مي شود.
دونكته در اينجا حائز اهميت است:
1- در هر تابعي تنها مي توان يكبار از params استفاده كرد.
2- پس از بكار بردن params ديگر نمي توان هيچ آرگوماني را تعريف كرد.

يكي از مثالهايي كه در اين زمينه مي توان ارائه داد استفاده از آرايه ها به عنوان آرگومان ورودي است. در اين حالت يا مي توان يك آرايه را به صورت كامل به تابع معرفي كرد و يا تنها نام آنرا به تابع پاس كرد. مثال زير را ملاحظه كنيد :

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex17 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

using System;

namespace ex17
{
class Class1
{
public static void UseParams(params int[] list)
{
for ( int i = 0 ; i < list.Length ; i++ )
Console.WriteLine(list[i]);
Console.WriteLine();
}

[STAThread]
static void Main(string[] args)
{
UseParams(1, 2, 3);

int[] myarray = new int[3] {10,11,12};
UseParams(myarray);

Console.ReadLine();

}
}
}

توضيحاتي در مورد كد فوق :

1- در تابع main به دو صورت از تابع UseParams ما استفاده شده است. يا اينكه خيلي ساده هر تعداد آرگومان را مي توان به تابع فرستاد و يا اينكه در ادامه آرايه ايي رسما تعريف و سپس به تابع فرستاده شود.
2- نحوه ي تعريف و استفاده از آرايه ها به صورت آرگومان ورودي را نيز مي توان در مثال فوق آموخت

+ نوشته شده در  جمعه بیست و سوم تیر 1385ساعت 13:6  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت هفتم

تعريف متدها در سي شارپ

در اين قسمت به يكي از مهمترين مباحث برنامه نويسي سي شارپ مي رسيم.
متدها در سي شارپ و يا همان توابع در زبان C ، اعضاي يك شيء يا كلاس هستند و مجموعه اي از يك سري از كارها را انجام مي دهند. فرض كنيد در برنامه ي شما ، قسمتي بايد يك عمليات رياضي خاص را انجام دهد و اين قسمت از كد كه شامل چندين خط نيز مي گردد بايد بارها و بارها در برنامه صدا زده شود. براي نظم بخشيدن به برنامه ، آنها را مي توان به صورت توابع بسته بندي كرد و بجاي نوشتن چندين خط تكراري، فقط نام اين بسته ( تابع ) و پارامترهاي آن را فراخواني نمود.

در سي شارپ يك تابع به صورت زير تعريف مي شود :

(نوع و اسامي پارامترها) نام تابع نوع خروجي تابع سطح دسترسي به تابع
}
بدنه ي تابع
{

براي تعريف يك متد يا تابع ابتدا سطح دسترسي به آن مانند public و private سپس نوع خروجي تابع مانند void ( هيچي ) ذكر مي گردد كه داخل اين پرانتزها مي توان ورودي هاي تابع يا بقولي آرگومان هاي ورودي را معرفي كرد. سپس تابع بايد با { شروع و با يك } خاتمه يابد.

براي مثال :

public int myFunc( int x )
{
...….
}

هر تابعي مي تواند صفر تا تعداد بيشماري آرگومان ورودي و صفر تا تعداد بيشماري خروجي داشته باشد. بوسيله يك تابع مي توان پيچيدگي كار را مخفي كرد و صرفا با صدا زدن نام آن ، يك سري از عمليات را انجام داد. گاهي از اوقات لازم مي شود دو يا چند تابع با يك نام داشته باشيم بطوريكه پارامترهاي ورودي يا مقادير خروجي و يا نوع آرگومان هاي ورودي آنها با هم متفاوت باشد به اين كار overloading مي گويند.
بسياري از كلاس هاي دات نت فريم ورك متدها و يا توابع مفيد حاضر و آماده اي را دارند. براي مثال كلاس DateTime ، متدي به نام ToLongDatastring دارد كه تاريخ را به صورت يك رشته طولاني بر مي گرداند.

توابع void :

توابعي كه با نوع void معرفي مي شوند هيچ خروجي ندارند و در زبان ويژوال بيسيك به آْنها sub و در دلفي به آنها procedure مي گويند.

بازگرداندن يك مقدار از يك تابع :

پس از اينكه عمليات يك مجموعه از كدها درون تابع به پايان رسيد با استفاده از كلمه ي return مي توان خروجي تابع را معرفي كرد. لازم به ذكر است ، هرجايي اين كلمه ي return ذكر شود كار تابع خاتمه مي يابد.

بهتر است موارد فوق را با چند مثال مرور كنيم :

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex13 انتخاب نماييد. در اينجا مي خواهيم تابعي را تعريف كنيم كه سه برابر جذر يك عدد را بر مي گرداند.

using System;

namespace ex13
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine( int3SQL(3) );
Console.ReadLine();
}

public static double int3SQL( double intInput )
{
double i=0;
i = Math.Sqrt( intInput );
return i;
}
}
}

توضيحاتي در مورد كد فوق :

1- از شيء Math در سي شارپ مي توان براي انجام يك سري عمليات رياضي ابتدايي استفاده كرد. در اينجا از متد جذر گرفتن آن استفاده شده است.
2- در تعريف تابع خودمان از كلمه ي كليدي static استفاده شده است. درون تابع Main نمي توان توابع غير استاتيك را فراخواني كرد. فعلا اين نكته را بخاطر را داشته باشيد تا در مقالات بعدي بيشتر راجع به آن صحبت شود.
3- بد نيست تابع تعريف شده را كمي بيشتر آناليز كنيم :

public static double int3SQL( double intInput )
{
double i=0;
i = Math.Sqrt( intInput );
return i;
}

ابتدا سطح دسترسي به تابع ذكر شده است. پابليك ، يعني اين تابع خارج از كلاس يك برنامه نيز قابل دسترسي است. سپس از كلمه ي static استفاده گرديده كه توضيح مختصري را در مورد آن ملاحظه كرديد. در ادامه نوع خروجي تابع كه در اينجا double مي باشد معرفي گرديده است. دقت كنيد كه حتما بايد نوع تعريف شده با مقداري كه يك تابع بر مي گرداند يكسان باشد و گرنه با يك خطا برنامه متوقف مي شود. سپس نام تابع تعريف شده است. داخل پرانتز ها نوع و نام آرگوماني ارائه شده است كه در بدنه ي تابع استفاده مي گردد. اگر به تعداد بيشتري پارامتر و يا آرگومان نياز بود مي توان آنها را با , از هم جدا كرد.
پس از اينكه عمليات تابع خاتمه مي يابد با استفاده از return اين خروجي را معرفي مي نماييم.
براي استفاده از اين تابع به سادگي نام تابع و سپس پرانتزها به همراه يك عدد دلخواه را مي نويسم كه آنرا در متد Main برنامه مي توان مشاهده كرد.

تعريف توابع در كلاس هاي ديگر برنامه و نحوه ي استفاده از آنها :

يكي از زيبايي هاي برنامه نويسي شيء گرا نظم و ترتيب و بسته بندي كارها مي باشد كه اصطلاحا در اينجا به آن encapsulation مي گويند. يعني ما يك سري از توابع و خواص را درون كپسولي به نام كلاس قرار مي دهيم تا به سادگي بارها و بارها از آن استفاده نماييم.
براي اينكار به سادگي يك توابع را به صورت معمول درون كلاس تعريف مي نماييم و سپس همانند خواص كه در مورد آنها صحبت شد ، از توابع مي توان استفاده كرد با اين تفاوت كه هنگام كار با توابع حتي اگر آنها هيچ آرگومان و يا پارامتر ورودي هم نداشته باشند ذكر پرانتزها الزامي است.

مثالي ديگر در اين زمينه :

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex14 انتخاب نماييد. سپس از منوي پروژه يك كلاس جديد را به برنامه اضافه نماييد (نام آنرا clsTools بگذاريد) .

using System;

namespace ex14
{
public class clsTools
{
public clsTools()
{
}

public uint intCalc ( uint a , uint b )
{
uint c = Math.Min (a,b);
double x = Math.Sqrt(c) ;
uint w = Convert.ToUInt32 ( x);
return w;
}
}
}

سپس در متد Main برنامه مي توان به صورت زير از آن استفاده كرد :

using System;

namespace ex14
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
clsTools m_var = new clsTools();
Console.WriteLine( m_var.intCalc(4,9));
Console.ReadLine();
}
}
}

توضيحاتي در مورد كد فوق :
1- تابع intCalc ما دو عدد صحيح مثبت را مي گيرد و سپس جذر كوچكترين دو عدد ورودي را محاسبه مي كند.
2- براي تبديل نوع هاي عددي مختلف به هم مي توان از شيء Convert استفاده كرد.
3- بدون استفاده از شيء Convert يكبار برنامه را اجرا كنيد و دليل خطاي بوجود آمده را بيان نماييد

+ نوشته شده در  جمعه بیست و سوم تیر 1385ساعت 13:5  توسط DevilHell  | 

مقدمه اي بر سي شارپ : قسمت ششم

دو  مورد تكميلي در مورد حلقه ها در سي شارپ :

1- هر جايي خواستيد به هر دليلي حلقه را پايان دهيد مي توانيد از دستور break; استفاده كنيد. در اين حالت به صورت آني حلقه خاتمه يافته و كدهاي ادامه ي برنامه پس از حلقه اجرا مي شوند.
2- نحوه ي استفاده از دستور continue : فرض كنيد حلقه ي شما در راند 15 خودش است! حالا در اين راند شما مي خواهيد يك سري از دستورات درون حلقه اجرا نشوند و حلقه به راند بعدي منتقل شده و كارش را ادامه دهد. اينجا است كه از دستور continue استفاده مي شود. بهتر است به يك مثال ساده در اين زمينه توجه كنيم.

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex11 انتخاب نماييد. سپس كد زير را درون آن بنويسيد :

using System;

namespace ex11
{
class Class1
{
[STAThread]
static void Main(string[] args)
{

Console.WriteLine(
"for (int i = 1; i <= 100; i++) -> break at i==5" );
for (int i = 1; i <= 100; i++)
{
if (i == 5)
break;
Console.WriteLine(i);
}
Console.ReadLine();


Console.WriteLine(
"for (int i = 1; i <= 10; i++) -> continue if i<9" );
for (int i = 1; i <= 10; i++)
{
if (i < 9)
continue;
Console.WriteLine(i);
}
Console.ReadLine();

}
}
}

موارد تكميلي مربوط به رد و بدل كردن مقادير به/از كلاس ها :

در قسمت بعدي مي خواهيم خاصيتي را تعريف كنيم كه يك مقدار را از كاربر مي گيرد و در برنامه مي توان توسط قسمت هاي ديگر از آن استفاده كرد.

ابتدا يك متغير عمومي بايد در سطح كلاس تعريف كرد تا مقدار دريافت شده توسط set را در خود نگاه داري كند (در مورد scope متغيرها ( متغيرهاي عمومي و محلي و امثال اينها) در هنگام معرفي توابع بيشتر بحث خواهد شد) . سپس از طريق كلمه ي كليدي value مقدار دريافت شده به متغير انتساب مي يابد و چون در سطح كلاس عمومي است در تمام كلاس قابل درسترسي است.

مثال : يك برنامه ي سي شارپ جديد console را در VS.NET باز كنيد و نام آنرا درابتدا ex12 انتخاب نماييد. سپس از منوي پروژه يك كلاس جديد به آن اضافه نماييد (به نام clsDate) و كد زير را درون آن بنويسيد :

using System;

namespace ex12
{
public class clsDate
{
private int Year;

public clsDate()
{
}

public int setYear
{
set
{
Year = value;
}
}

public bool IsLeapYear
{
get
{
return System.DateTime.IsLeapYear(Year);
}
}


}
}

براي استفاده از آن در متد main برنامه به صورت زير عمل مي كنيم:

using System;

namespace ex12
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
clsDate m_var = new clsDate();

m_var.setYear = 1990;

if (m_var.IsLeapYear)
Console.WriteLine("1990 is a leap year.");
else
Console.WriteLine("1990 is not a leap year.");

Console.ReadLine();
}
}
}

توضيحاتي در مورد كد فوق:

1- نحوه ي تعريف متغير از يك كلاس جزو اساسي ترين قسمت هاي كار با يك كلاس محسوب مي شود كه در قسمت هاي پيشين نيز معرفي گرديد.
2- هنگامي كه از if استفاده مي كنيم لزومي ندارد حتما بنويسيم m_var.IsLeapYear==true . همين كه اين خاصيت ذكر مي شود در وهله ي اول true بودن آن چك خواهد شد.
3- نحوه ي مقدار دهي به يك خاصيت را هم در كد فوق ملاحظه مي نماييد. در هنگام استفاده از خاصيت ها نيازي به آوردن پرانتزها () در مقابل نام آنها وجود ندارد.
4- براي مرور ، نحوه ي معرفي خاصيت ها با get نيز بيان گرديد. با استفاده از set و get مي توان به كلاس ها ، مقادير متغيرها را پاس كرد و يا مقداري را دريافت نمود.

+ نوشته شده در  جمعه بیست و سوم تیر 1385ساعت 13:2  توسط DevilHell  |