ایران سرفراز- نرم افزار وپروژهای دانشجویی


نرم افزار وپروژهای دانشجویی

فصل بیست و چهارم ریسمان ها و همگام سازی #C

<!-- /* Font Definitions */ @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:1; mso-generic-font-family:roman; mso-font-format:other; mso-font-pitch:variable; mso-font-signature:0 0 0 0 0 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman","serif"; mso-fareast-font-family:"Times New Roman";} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; font-size:10.0pt; mso-ansi-font-size:10.0pt; mso-bidi-font-size:10.0pt;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0; mso-gutter-direction:rtl;} div.Section1 {page:Section1;} -->

            فصل بیست و چهارم

C# ریسمان ها و همگام سازی

آنچه که در این فصل یاد خواهید گرفت:

آشنایی با برنامههای چندوظیفهگی و نحوهی برنامهنویسی آنها

آشنایی با برنامهنویسی چندریسمانی

همگامسازی ریسمانها

قفل کردن منبع مختلف برای جلوگیری از دسترسی مخرب ریسمانهای همگام

کار با مانیتورها

یک مجموعه از System.Threading ریسمانها مسئول چند وظیف ه گی یک برنام ه ی کاربردی واحد هستن د . فضای نامی

کلاس ها و واس ط ها را برای مدیریت برنام ه نویسی چند ریسمانی فراهم م ی کند. احتمالاً اکثر برنام ه نویس ها هرگز نیازی به

پشتیبانی ریسمان بندی را در داخل کلا س ها بصورت انتزاعی درم ی آورد تا CLR مدیریت صریح ریسما ن ها نداشتند، چون

چندریسمانی را ساده سازد.

بخش اول این فصل نحو ه ی ایجاد، مدیریت و از بین برد ن 1 ریسمان ها را نشان می دهد. حتی اگر ریسمان های خود را صریحاً

ایجاد نکرده باشند، م ی خواهید مطمئن باشید که کد شما م ی تواند چند ریسمانی را اداره کن د . اگر در یک محیط

چندریسمانی 2 اجرا شود یا در قطعاتی که ممکن است توسط برنام ه نویسان دیگر در برنام ه های چندریسمانی استفاده شوند،

باید این ایده را در نظر گرف ت . این عمل برای توسع ه دهندگان سروی س های وب و کنترل از راه دور مهم اس ت . اگرچه

برنامه های تحت وب اکثر ویژگ ی های برنامه های رومیزی را دارند، آنها روی یک سرور اجرا م ی شوند و بایستی اید ه های

بهره وری و چندریسمانی برای آنها در نظر گرفته شود.

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

محدود کردن دسترسی به آن منبع در یک لحظه توسط یک ریسمان لازم باشد.

یک شباهت کلاسیک، توالت هواپیما اس ت . می خواهید دسترسی به توال ت را در هر لحظه فقط برای یک نفر مجاز داری د . این

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

1 Kill

2 MultiThread

Mohsen_mahyar@yahoo.com - C# برنامه نویسی

440

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

فرد دیگر از صف خارج شده و منبع را م یگیرد و آن را قفل م یکند.

گاهی اوقات، ممکن است ریسما ن های متعددی بخواهند به یک منبع در برنام ه ی شما دسترسی داشته باشن د (همچون یک

فایل). شاید مهم باشد مطمئن شوید که در هر لحظه فقط یک ریسمان به منبع دسترسی د ارد و منبع خود را قفل کرده و بعد

از دستیابی یک ریسمان به آن، منبع را آزاد کنی د . قفل های برنامه نویسی با توجه به توزیع منابع م ی توانند بسیار پیچیده

باشند.

-1-24 ریسمان ها

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

را با 10 بلیون رقم اعشار حساب کنی د . بعد از شروع این محاسبه، تا زمانی که آن کار م ی کند، برنامه هیچ Pi می خواهید

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

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

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

اجرایی دیگری لازم دارید.

کاربرد معمول دیگر از ریسما ن بندی، در صورتی است که باید منتظر یک رویداد بمانی د : همچون ورودی کاربر، خواندن از فایل

یا دریافت داده از شبک ه . در حالیکه پروس ه ی شما منتظر است، آزاد کردن پردازنده برای شروع اجرای عمل دیگر، یک ایده

خوب است و آن اجرای برنامه شما را سریع تر می سازد.

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

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

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

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

-1-1-24 شروع ریسما نها

یک آرگومان از نوع Thread است. سازندهی Thread ساده ترین راه ایجاد یک ریسمان، ایجاد یک نمونه جدید از کلاس

را برای این منظور تهیه کرده است، که به متد مورد نظر شما اشاره ThreadStart کلاس نماینده CLR . نماینده می گیرد

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

بصورت زیر است. ThreadStart کن". اعلان نمایندهی

public delegate void ThreadStart();

void همانطور که می بینید متدی که شما به این نماینده الحاق م ی کنید، نباید پارامتری داشته باشد و مقدا ر

برمیگرداند.پس یک ریسمان جدید را بصورت زیر ایجاد میکنید.

Thread myThread = new Thread( new ThreadStart(myFunc) );

برای مثال: می خواهیم دو ریسمان ایجاد کنیم که یکی از صفر به بالا می شمارد و دیگری از 1000 به پایین می شمارد.

public void Incrementer()

{

for (int i =0;i<1000;i++)

{

Console.WriteLine("Incrementer: {0}", i);

}

فصل بیست و چهارم ریسما نها و همگام سازی

441

}

public void Decrementer()

{

for (int i = 1000;i>=0;i--)

{

Console.WriteLine("Decrementer: {0}", i);

}

}

مقداردهی ThreadStart برای اجرای این متدها در ریسمانها، دو ریسمان جدید ایجاد کنید و هرکدام را با یک نمایند ه ی

اولیه کنید. این نمایندهها در ابتدا با توابع عضو مربوطه مقداردهی اولیه م یشوند.

Thread t1 = new Thread( new ThreadStart(Incrementer) );

Thread t2 = new Thread( new ThreadStart(Decrementer) );

Thread مربوطه به شی Start با ایجاد نمون ه هایی از ریسما ن ها، اجرای آنها شروع نم ی شود. برای انجام این کار، باید متد

فراخوانی شود.

t1.Start();

t2.Start();

توجه: اگر کار دیگری انجام ندهد، بعد از اینکه تابع تمام شود، ریسمانها متوقف م یگردند.

System.Threading Using 1 یک برنامهی کامل و خروجی آن را نشان میدهد. لازم است با یک دستور - مثال 24

1 سوئیچ t 2 و t با خبر سازید. به خروجی توجه کنید، م ی توانید ببینید که پردازنده ما بین Thread کامپایلر را از وجود کلاس

می کند.

1- مثال 24

#region Using directives

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

#endregion

namespace UsingThreads

{

class Tester

{

static void Main( )

{

// make an instance of this class

Tester t = new Tester( );

Console.WriteLine( "Hello" );

// run outside static Main

t.DoTest( );

}

public void DoTest( )

{

// create a thread for the Incrementer

// pass in a ThreadStart delegate

// with the address of Incrementer

Thread t1 =

new Thread(

new ThreadStart( Incrementer ) );

// create a thread for the Decrementer

// pass in a ThreadStart delegate

// with the address of Decrementer

Thread t2 =

new Thread(

new ThreadStart( Decrementer ) );

Mohsen_mahyar@yahoo.com - C# برنامه نویسی

442

// start the threads

t1.Start( );

t2.Start( );

}

// demo function, counts up to 1K

public void Incrementer( )

{

for ( int i = 0; i < 1000; i++ )

{

System.Console.WriteLine(

"Incrementer: {0}", i );

} }

// demo function, counts down from 1k

public void Decrementer( )

{

for ( int i = 1000; i >= 0; i-- )

{

System.Console.WriteLine(

"Decrementer: {0}", i );

} } } }

Output (excerpt):

Incrementer: 102

Incrementer: 103

Incrementer: 104

Incrementer: 105

Incrementer: 106

Decrementer: 1000

Decrementer: 999

Decrementer: 998

Decrementer: 997

ابتدا پردازنده به اولین ریسمان اجازه م ی دهد تا شمردن 106 اجرا گردد. سپس ریسمان دوم مشارکت کرده و شمردن از 1000

به پایین را آغاز م ی کند. سپس به اولین ریسمان اجاز ه ی اجرا دا د ه می شود. مدت زمان واقعی اختصاص داده شده به هر

ریسمان بوسیله زما ن بند ریسمان اداره م ی شود و به فاکتورهای زیادی بستگی اس ت : همچون سرعت پردازنده، درخواست

پردازنده از طرف برنامه های دیگر.

-2-1-20 پیوندزدن ریسمان ها

زمانی که م ی خواهید به یک ریسمان بگویید تا اجر ای کامل ریسمان دیگر منتظر بماند، ریسمان اول را به ریسمان دوم پیوند

زنید، یعنی سر ریسمان اول را به ته ریسمان دوم پیوند زدید.

2) بنویسید. t) 1) به ریسمان 2 t) برای پیوند زدن ریسمان 1

t2.Join( );

2 منتظر خواهد مان د . برای مثال، t 1 مکث خواهد کرد و برای ت ک میل و خروج t ، 1 اجرا شود t اگر این دستور در یک متد در

از ریسمان بخواهد تا اتمام همه ریسما ن های دیگر منتظر بماند قبل از اینکه آن پیام ،()Main ممکن است در بدن ه ی متد

ایجاد کرد ه اید . MyThreads مندرج شده را بنویس د . در تکه کد بعدی، فرض کنید یک کلکسیون از ریسما ن ها بنام

کلکسیون را طی میکند و ریسمان جاری را به همه ریسما نهای کلکسیون پیوند میزند.

foreach (Thread myThread in myThreads)

فصل بیست و چهارم ریسما نها و همگام سازی

443

{

myThread.Join();

}

Console.WriteLine("All my threads are done.");

پیام آخری تا زمانیکه همه ریسما ن ها پایان نیافت ه اند، اجرا نخواهد ش د . در یک محیط تولید، ممکن است یک دنباله از

ریسمان ها را برای بنا کردن بعضی کارها شروع کنید و ادامه اجرای ریسمان اصلی را تا کامل شدن همه ریسما ن ها متوقف

سازید.

Sleep -3-1-20 بلوکه کردن ریسمان ها با

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

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

هزاران میلیون سیکل ماشین نمایش دهید.

می شود . یک نسخه از آن overload یک متد ایستای عمومی برای این منظور پیشنهاد م یکند. این متد Thread کلاس

را به عنوان ورودی م ی گیرد. هر کدام مقدار زمان معلق کردن timeSpan و نسخه ی دیگر آن یک ش ی int یک مقدار

ریسمان را با واحد میلیونم ثانیه نمایش م یدهند. (مقدار صحیح 2000 یعنی 2 ثانیه)

میلی ثانیه اس ت . ()Sleep می توانند تیک ها ( 100 نانو ث انیه) را اندازه گیری کنند، واحد داد ه ها در متد timespan اگرچه اشیاء

را احضار کنید که ()Thread.Sleep برای اینکه ریسما ن تان را به یک ثانیه خواب وادار کنید، م ی توانید متد ایستای

ریسمان احضار شده را معلق م یسازد.

Thread.Sleep(1000);

را با مقدار صفر فراخوانی م ی کنند. بدین منظور که به زما ن بند ریسمان القاء کنند، نوبت اجرا را به Sleep گاهی اوقات، متد

ریسمانی دیگر بدهد، حتی اگر زمانبند مقدار بیشتری زمان به ریسمان شما داده باشد.

تغییر دهید، خروجی تغییر Writeln 1) بعد از هر دستور Thread.Sleep( 1 را با اضافه کردن یک دستور - اگر مثال 24

می یابد.

for (int i =0;i<1000;i++)

{

Console.WriteLine( "Incrementer: {0}", i);

Thread.Sleep(1);

}

این تغییر کوچک کافی است تا هر ریسمان بعد از چاپ یک مقدار توسط ریسمان دیگر، فرصت اجرا پیدا کن د . خروجی این

تغییر را منعکس می کند.

Incrementer: 0

Incrementer: 1

Decrementer: 1000

Incrementer: 2

Decrementer: 999

Incrementer: 3

Decrementer: 998

Incrementer: 4

Decrementer: 997

Incrementer: 5

Decrementer: 996

Mohsen_mahyar@yahoo.com - C# برنامه نویسی

444

Incrementer: 6

Decrementer: 995

-4-1-24 از بینبردن ریسمان ها

معمولاً، ریس مان ها بعد از اجرای دورهی خود از بین می روند. می توانید از یک ریسمان بخواهید خود را از بین ببر د .

است که ریسمان بصورت دور ه ای آن را بررسی م ی کند. زمانی که حالت KeepAlive واضح ترین روش تنظیم فلگ بولین

فلگ تغییر یابد، ریسمان می تواند خود را متوقف سازد.

است، که از ریسمان م ی خواهد خود را از بین ببر د . نهایتاً در لاعلاجی و اگر ()Thread.Interupt روش د یگر فراخوانی

را فراخوانی کنی د . این عمل یک استثنای Thread. Abort برنامه بخواهد خود را متوقف سازد، ممکن است

رها می کند، که ریسمان م ی تواند تشخیص ده د. ریسمان با استثنای ThreadAbortException

بصورت یک سیگنال برخورد م ی کند تا فوراً ریسمان را از بین بر د . در هر حال، شما شبیه یک ThreadAbortException

سیاست خودکشی، ریسمان را نم یکشید.

ریسمان را از بین ببری د . ممکن است ،Cancel ممکن است بخواهید در واکنش به یک رویداد همچون کلیک کارب ر روی دکمه

2 باشد . در اداره کنند ه ی t 1 باشد و رویدادی که لغو م ی شود در ریسمان t در ریسمان Cancel اداره کننده ی رویداد دکمه

1 فراخوانی کنید. t را روی Abort رویدادتان می توانید

t1.Abort();

1 می تواند آنرا تشخیص دهد. t 1 رها می شود که t یک استثناء در متد جاری

ذخیره می شوند . قبل از شروع ریسما ن ها Thread 2 سه ریسمان ایجاد م ی شوند و در یک آرایه از اشیاء - در م ثال 24

قرار دهید )ریسمان های زمینه دقیقاً شبیه ریسما ن های پیش زمینه اجرا م ی شوند True آنها را IsBackground خصوصیات

به استثناء اینکه آنها نم ی توانند مانع خاتمه یاف ت ن یک پردازش شون د (. هر ریسمان نامگذاری شده و شروع م ی شود )همچون

2. یک پیام برای نشان دادن شروع ریسمان نمایش داده م ی شود و سپس ریسمان اصلی قبل از شروع Thread) 1 و Thread

ریسمان بعدی 50 میلی ثانیه خواب می رود.

کنار گذاشته م ی شود. سپس ،()Abort بعد از شروع سه ریسمان، 50 میلی ثانیه دیگر م ی گذرد و اولین ریسمان با فراخوانی

ریسمان اصلی هر سه ریسمان در حال اجرا را بهم پیوند م ی زند. اثر عمل این است که تا زمانیکه همه ریسما ن های دیگر کامل

All My Thread Are نشده ____________اند، ریسمان اصلی ادامه نخواهد یافت. زمانی که آنها کامل شوند، ریسمان اصلی یک پی ا م

2 نمایش داده می شود. - را چاپ می کند. کد منبع کامل در مثال 24 Done

2- مثال 24

#region Using directives

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

#endregion

namespace InterruptingThreads

{

class Tester

{

static void Main( )

{

// make an instance of this class

Tester t = new Tester( );

// run outside static Main

t.DoTest( );

فصل بیست و چهارم ریسما نها و همگام سازی

445

}

public void DoTest( )

{

// create an array of unnamed threads

Thread[] myThreads =

{

new Thread( new ThreadStart(Decrementer) ),

new Thread( new ThreadStart(Incrementer) ),

new Thread( new ThreadStart(Decrementer) ),

new Thread( new ThreadStart(Incrementer) )

};

// start each thread

int ctr = 1;

foreach (Thread myThread in myThreads)

{

myThread.IsBackground = true;

myThread.Start( );

myThread.Name = "Thread" + ctr.ToString( );

ctr++;

Console.WriteLine("Started thread {0}",

myThread.Name);

Thread.Sleep(50);

}

// ask the first thread to stop

myThreads[0].Interrupt( );

// tell the second thread to abort immediately

myThreads[1].Abort( );

// wait for all threads to end before continuing

foreach (Thread myThread in myThreads)

{

myThread.Join( );

}

// after all threads end, print a message

Console.WriteLine("All my threads are done.");

}

// demo function, counts down from 100

public void Decrementer( )

{

try

{

for (int i = 100; i >= 0; i--)

{

Console.WriteLine(

"Thread {0}. Decrementer: {1}",

Thread.CurrentThread.Name,

i);

Thread.Sleep(1);

}

}

catch (ThreadAbortException)

{

Console.WriteLine(

"Thread {0} aborted! Cleaning up...",

Thread.CurrentThread.Name);

}

catch (System.Exception e)

{

Console.

WriteLine("Thread has been interrupted ");

}

finally

Mohsen_mahyar@yahoo.com - C# برنامه نویسی

446

{

Console.WriteLine(

"Thread {0} Exiting. ",

Thread.CurrentThread.Name);

} }

// demo function, counts up to 100

public void Incrementer( )

{

try

{

for (int i = 0; i < 100; i++)

{

Console.WriteLine(

"Thread {0}. Incrementer: {1}",

Thread.CurrentThread.Name,

i);

Thread.Sleep(1);

}

}

catch (ThreadAbortException)

{

Console.WriteLine(

"Thread {0} aborted!",

Thread.CurrentThread.Name);

}

catch (System.Exception e)

{

Console.

WriteLine("Thread has been interrupted");

}

finally

{

Console.WriteLine(

"Thread {0} Exiting. ",

Thread.CurrentThread.Name);

}}}}

Output (excerpt):

Started thread Thread1

Thread Thread1. Decrementer: 100

Thread Thread1. Decrementer: 99

Started thread Thread2

Thread Thread2. Incrementer: 0

Thread Thread1. Decrementer: 98

Started thread Thread3

Thread Thread3. Decrementer: 100

Thread Thread1. Decrementer: 97

Thread Thread2. Incrementer: 1

Started thread Thread4

Thread Thread4. Incrementer: 0

Thread Thread2 aborted!

Thread Thread3. Decrementer: 99

Thread Thread2 Exiting.

Thread has been interrupted

Thread Thread3. Decrementer: 98

Thread Thread4. Incrementer: 1

فصل بیست و چهارم ریسما نها و همگام سازی

447

Thread Thread1 Exiting.

Thread Thread3. Decrementer: 97

Thread Thread3. Decrementer: 1

Thread Thread4. Incrementer: 98

Thread Thread3. Decrementer: 0

Thread Thread4. Incrementer: 99

Thread Thread3 Exiting.

Thread Thread4 Exiting.

All my threads are done.

دیدید که ابتدا ریسمان اول شروع م ی شود و از 100 تا 99 می شمارد . سپس ریسمان دوم شروع م ی شود تا زمانیکه

2 گزارش thread ، ریسمان های سوم و چهارم آغاز شوند، این دو ریسمان با هم اجرا م ی شوند. بعد از یک مدت زمان کو تاه

1 گزارش thread می دهد که کنار گذاشته شده است و سپس گزارش م ی دهد در حال خروج اس ت . بعد از زمان کمتری

فی الفور Abort می دهد دچار وقفه شده اس ت . چون وقفه، ریسمان را در یک حالت انتظار نگه م ی دارد، اجرای آن به انداز ه ی

نیست.

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

ریسمانها پیوند خورده بود، با چاپ پیام خروج خود ادامه می یابد.

-2-24 همگام سازی

گاهی اوقات، ممکن است بخواهید دسترسی به یک منبع همچون خصوصیات و متدهای یک ش ی را کن ت رل کنید، تا اینکه در

هر لحظه فقط یک متد بتواند آن منبع را استفاده یا تغییر ده د . شی شما شبیه توالت هواپیما است و ریسما ن های مرتبط

شبیه افراد منتظر در صف هستن د . همگامسازی با یک قفل روی ش ی فراهم م ی شود. این عمل به توسع ه دهنده کمک م ی کند

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

در ابتدا .Moniter و کلاس ،#C در lock دستور ،InterLock این بخش سه مکانیزم همگا م سازی را بررسی م ی کند: کلاس

.(Counter شما به ایجاد یک منبع اشتراکی نیاز داری د ( اغلب یک فایل یا چاپگر یا در حالت س اده یک متغیر صحیح بنام

را در هر دو ریسمان افزایش خواهید داد. Counter شما مقدار

برای شروع، متغیر عضو را اعلان کرده و آنرا با صفر مقداردهی کنید.

int counter = 0;

تغییر دهید. Counter را برای افزایش متغیر عضو Incrementer متد

public void Incrementer()

{

try

{

while (counter < 1000)

{

int temp = counter;

temp++; // increment

// simulate some work in this method

Thread.Sleep(1);

// assign the Incremented value

// to the counter variable

// and display the results

counter = temp;

Console.WriteLine(

"Thread {0}. Incrementer: {1}",

Mohsen_mahyar@yahoo.com - C# برنامه نویسی

448

Thread.CurrentThread.Name,

counter);

}}

هدف ما در اینجا شبی ه سازی کاری است که ممکن است با یک منبع کنترل شده انجام م ی شود. عیناً همانطور که ممکن است

یک فایل را باز کنید، محتوای آن را تغییر داده و آن را ببندید.

را به یک متغیر موقتی خوانده و متغیر موقتی را افزایش دهید و برای شبی ه سازی این کار یک میلی Counter در اینجا م قدار

برگردانید. Counter ثانیه آنرا بخوابانید و سپس مقدار افزایش یافته را به

0) را می خواند و آن را به یک متغیر موقت انتساب م یدهد. سپس مقدار Counter ( مشکل این است که ریسمان اول مقدار

0) را Counter ( متغیر موقت را افزایش می دهد. زمانی که آن ریسمان کارش را انجام م ی دهد، ریسمان دوم مقدار

می خواند و مقدار آن را به یک متغیر موقت انتساب م ی دهد. ریسمان اول کار خود را خاتمه داده و مقدار متغیر موقت ( 1) را به

انتساب داده و آنرا نمایش م ی دهد. ریسمان دوم نیز همان کار را انجام م ی دهد. 1و 1 چاپ م ی شود در دور بعدی، Counter

همان چیز اتفاق م ی افتد. به جای این که دو ریسمان مقادیر 1و 2و 3و 4و . . . را بشمارند، مقادیر 1و 2و 3و 3و 4و 4و . . . را چاپ

می کند.

3 خروجی و کد منبع کامل را برای این مثال نشان می دهد. - مثال 24

3- مثال 24

#region Using directives

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

#endregion

namespace SharedResource

{

class Tester

{

private int counter = 0;

static void Main( )

{

// make an instance of this class

Tester t = new Tester( );

// run outside static Main

t.DoTest( );

}

public void DoTest( )

{

Thread t1 = new Thread( new ThreadStart( Incrementer ) );

t1.IsBackground = true;

t1.Name = "ThreadOne";

t1.Start( );

Console.WriteLine( "Started thread {0}",

t1.Name );

Thread t2 = new Thread( new ThreadStart( Incrementer ) );

t2.IsBackground = true;

t2.Name = "ThreadTwo";

t2.Start( );

Console.WriteLine( "Started thread {0}",

t2.Name );

t1.Join( );

فصل بیست و چهارم ریسما نها و همگام سازی

449

t2.Join( );

// after all threads end, print a message

Console.WriteLine( "All my threads are done." );

}

// demo function, counts up to 1K

public void Incrementer( )

{

try

{

while ( counter < 1000 )

{

int temp = counter;

temp++; // increment

// simulate some work in this method

Thread.Sleep( 1 );

// assign the decremented value

// and display the results

counter = temp;

Console.WriteLine(

"Thread {0}. Incrementer: {1}",

Thread.CurrentThread.Name,

counter );

}}

catch ( ThreadInterruptedException )

{

Console.WriteLine(

"Thread {0} interrupted! Cleaning up...",

Thread.CurrentThread.Name );

}

finally

{

Console.WriteLine(

"Thread {0} Exiting. ",

Thread.CurrentThread.Name );

}}}}

Output:

Started thread ThreadOne

Started thread ThreadTwo

Thread ThreadOne. Incrementer: 1

Thread ThreadOne. Incrementer: 2

Thread ThreadOne. Incrementer: 3

Thread ThreadTwo. Incrementer: 3

Thread ThreadTwo. Incrementer: 4

Thread ThreadOne. Incrementer: 4

Thread ThreadTwo. Incrementer: 5

Thread ThreadOne. Incrementer: 5

Thread ThreadTwo. Incrementer: 6

Thread ThreadOne. Incrementer: 6

Interlocked -1-2-20 کاربرد

یک تعداد مکانیزم همگا م سازی فراهم م ی کند. آنها شامل ابزار همگا م سازی عمومی همچون بخ ش های بحرانی (با نام CLR

هستند. هر کدام در ادامهی این بخش بحث می شوند. Monitor و کلاس (NET قفل ها در

Mohsen_mahyar@yahoo.com - C# برنامه نویسی

450

افزایش و کاهش یک مقدار، یک الگوی برنام ه نویسی عمومی است و آن اغلب به حفاظت از طریق همگا م سازی نیاز دارد، که

فقط دو متد با نا م های Interlocked . فقط برای این منظور پیشنهاد م ی کند Interlocked یک کلاس خاص بنام CLR

دارد که علاوه بر افزایش و کاهش یک مقدار، کنترل همگا م سازی را نیر در نظر م ی گیرند. متد Decrement و Increment

3 را بصورت زیر تغییر دهید. - مثال 24 Incrementer

public void Incrementer( )

{

try

{

while (counter < 1000)

{

int temp = Interlocked.Increment(ref counter);

// simulate some work in this method

Thread.Sleep(0);

// display the incremented value

Console.WriteLine(

"Thread {0}. Incrementer: {1}",

Thread.CurrentThread.Name,

temp);

}}}

یک پارامتر ()InterLocked.Increment و مابقی برنامه عیناً مانند مثال قبلی اس ت . متد Finally و Catch بلوک های

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

همراه آن بکار برید.

را بگیرد. long یک نوع ، int م یشود و م یتواند به جای یک نوع Overload ، Increment() متد

همگام می شود و خروجی آن همان چیزی است که انتظار Counter زمانی که این تغییر انجام شود ، دسترسی به عضو

می رفت.

Output (excerpts):

Started thread ThreadOne

Started thread ThreadTwo

Thread ThreadOne. Incrementer: 1

Thread ThreadTwo. Incrementer: 2

Thread ThreadOne. Incrementer: 3

Thread ThreadTwo. Incrementer: 4

Thread ThreadOne. Incrementer: 5

Thread ThreadTwo. Incrementer: 6

Thread ThreadOne. Incrementer: 7

Thread ThreadTwo. Incrementer: 8

Thread ThreadOne. Incrementer: 9

Thread ThreadTwo. Incrementer: 10

Thread ThreadOne. Incrementer: 11

Thread ThreadTwo. Incrementer: 12

Thread ThreadOne. Incrementer: 13

Thread ThreadTwo. Incrementer: 14

Thread ThreadOne. Incrementer: 15

Thread ThreadTwo. Incrementer: 16

Thread ThreadOne. Incrementer: 17

Thread ThreadTwo. Incrementer: 18

Thread ThreadOne. Incrementer: 19

فصل بیست و چهارم ریسما نها و همگام سازی

451

Thread ThreadTwo. Incrementer: 20

-2-2-24 کاربرد قف لها

خوب است، در بعضی مواقع م ی خواهید InterLocked اگر بخواهید یک مقدار را افزایش یا کاهش دهید، اگرچه ش ی

دسترسی به منابع دیگر را نیز کنترل کنی د . چیزی که لازم است، یک مکا نیزم همگام سازی کلی م یباشد . این مکانیزم با

فراهم می شود. #C در lock ویژگی

یک بخش بحرانی از کد را علام ت گذاری می کند. همگامسازی روی ش ی برگزیده ی شما را با یک قفل فراهم م ی سازد . ،lock

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

دستورات آزاد می شود.

فراهم می کند. یک ارجاع به یک ش ی را به آن ارسال کرده و به lock پشتیبانی مستقیم قف ل ها را از طریق کلمه کلیدی #C

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

lock(expression) statement-block

بصورت زیر تغییر دهید. lock را با استفاده یک دستور Incrementer مثال: می توانید متد

public void Incrementer()

{

try

{

while (counter < 1000)

{

int temp;

lock (this)

{

temp = counter;

temp ++;

Thread.Sleep(1);

counter = temp;

}

// assign the decremented value

// and display the results

Console.WriteLine(

"Thread {0}. Incrementer: {1}",

Thread.CurrentThread.Name,

temp);

}}

و بقیه برنامه همانند مثال قبلی هستن د . خروجی این کد، مساوی خروجی تولید شده با Finally و Catch بلوک های

است. InterLocked استفاده از

-3-2-20 کاربرد مانیتورها

اشیاء استفاده شدة تاکنون، برای بیشتر نیازها کافی هستن د . برای کنترل پیشرفته روی منابع، ممکن است بخواهید یک

مانیتور بکار بری د . یک مانیتور به شما اجازه می دهد تصمیم بگیرید یک همگا م سازی کی وارد و کی خارج شود و به شما

اجازه می دهد برای آزادشدن فضای دیگری از کدتان منتظر بمانید.

را با ارسال شی موردنظر جهت قفل کردن، به ()Monitor.Enter زمانی که م ی خواهید همگام سازی را شروع کنید، متد

آن فراخوانی کنید.

Monitor.Enter(this);

Mohsen_mahyar@yahoo.com - C# برنامه نویسی

452

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

را ()Wait انجام دهید . در حالی که منتظر هستید مانیتور در دسترس قرار گیرد، مجدداً سعی کنی د . می توانید صریحاً

را برای بیدار ()Pulse فراخوانی کنید، که ریسمان شما را تا زمانیکه مانیتور مشغول است معلق م ی سازد و توسع ه دهنده

در کنترل نظم و ترتیب ریسما نها کمک می کند. ()Wait . کردن ریسمان معلق فراخوانی می کند

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

شده است. Download چاپ در زمینه انجام شود. اما می خواهید مطمئن شوید قبل از شروع عمل چاپ حداقل 10 صفحه

ریسمان چاپ شما منتظر خواهد ماند تا زمانیکه ریسمان گرفتن فایل، خوانده شدن اندازة کافی از فایل را سیگنال ده د .

کنید، چون احتمال دارد فایل صدها صفحه باشد و نم ی خواهید تا پایا ن یافتن عمل Join نمی خواهید ریسمان گرفتن فایل را

شده است . متد Download منتظر بما نید. اما می خواهید مطمئن شوید، قبل از چاپ فایل حداقل 10 صفحه از آن Download

عین یک بلیط است. ()Wait

تا 10 به Incrementer . را به آن اضافه کنی د Decrementer را مجدداً بنویسید و متد Tester برای شبیه سازی این مورد

به پایین تا صفر م ی شمارد. شما کاهش شمارنده را شروع نم ی کنید، مگر اینکه مقدار Decrementer بالا می شمارد و متد

حداقل 5 باشد. counter

را بررسی کنید، اگر کمتر از 5 باشد، متد counter را روی مانیتور فراخوانی کنی د . سپس مقدار Enter ،Decrementer در

را روی مانیتور فراخوانی کنید. ()Wait

if (counter < 5)

{

Monitor.Wait(this);

}

سیگنال می دهد زمانی که مانیتور آزاد شود، مجددا برگرد د . اگر ریسمان CLR مانیتور را آزاد م ی کند. اما به ،()Wait فراخوانی

را فراخوانی کند، ریسما نهای منتظر یک شانس برای اجرای مجدد دریافت م یکنند. Pulse فعال

Monitor.Pulse(this);

سیگنال می دهد که تغییری در حالت رخ داده است، که ممکن است یک ریسمان منتظر را آزاد ساز د . CLR به ()Pulse متد

()Exit زمانی که یک ریسمان مربوط به مانیتور پایان م ی یابد، آن باید انتهای ناحی ه ی کد کنترل شده را با فراخوانی

علامتگذاری کند.

Monitor.Exit(this);

Monitor را با استفاده از counter 4 شبیه سازی را ادامه م ی دهد. یک دسترسی همگا م سازی شده بر یک متغیر - مثال 24

فراهم می سازد.

4- مثال 24

#region Using directives

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

#endregion

namespace UsingAMonitor

{

class Tester

{

private long counter = 0;

static void Main( )

{

// make an instance of this class

فصل بیست و چهارم ریسما نها و همگام سازی

453

Tester t = new Tester( );

// run outside static Main

t.DoTest( );

}

public void DoTest( )

{

// create an array of unnamed threads

Thread[] myThreads =

{

new Thread( new ThreadStart(Decrementer) ),

new Thread( new ThreadStart(Incrementer) )

};

// start each thread

int ctr = 1;

foreach ( Thread myThread in myThreads )

{

myThread.IsBackground = true;

myThread.Start( );

myThread.Name = "Thread" + ctr.ToString( );

ctr++;

Console.WriteLine( "Started thread {0}", myThread.Name );

Thread.Sleep( 50 );

}

// wait for all threads to end before continuing

foreach ( Thread myThread in myThreads )

{

myThread.Join( );

}

// after all threads end, print a message

Console.WriteLine( "All my threads are done." );

}

void Decrementer( )

{

try

{

// synchronize this area of code

Monitor.Enter( this );

// if counter is not yet 10

// then free the monitor to other waiting

// threads, but wait in line for your turn

if ( counter < 10 )

{

Console.WriteLine(

"[{0}] In Decrementer. Counter: {1}. Gotta Wait!",

Thread.CurrentThread.Name, counter );

Monitor.Wait( this );

}

while ( counter > 0 )

{

long temp = counter;

temp--;

Thread.Sleep( 1 );

counter = temp;

Console.WriteLine(

"[{0}] In Decrementer. Counter: {1}. ",

Thread.CurrentThread.Name, counter );

}}

finally

{

Monitor.Exit( this );

}}

Mohsen_mahyar@yahoo.com - C# برنامه نویسی

454

void Incrementer( )

{

try

{

Monitor.Enter( this );

while ( counter < 10 )

{

long temp = counter;

temp++;

Thread.Sleep( 1 );

counter = temp;

Console.WriteLine(

"[{0}] In Incrementer. Counter: {1}",

Thread.CurrentThread.Name, counter );

}

// I'm done incrementing for now, let another

// thread have the Monitor

Monitor.Pulse( this );

}

finally

{

Console.WriteLine( "[{0}] Exiting...",

Thread.CurrentThread.Name );

Monitor.Exit( this );

}}}}

Output:

Started thread Thread1

[Thread1] In Decrementer. Counter: 0. Gotta Wait!

Started thread Thread2

[Thread2] In Incrementer. Counter: 1

[Thread2] In Incrementer. Counter: 2

[Thread2] In Incrementer. Counter: 3

[Thread2] In Incrementer. Counter: 4

[Thread2] In Incrementer. Counter: 5

[Thread2] In Incrementer. Counter: 6

[Thread2] In Incrementer. Counter: 7

[Thread2] In Incrementer. Counter: 8

[Thread2] In Incrementer. Counter: 9

[Thread2] In Incrementer. Counter: 10

[Thread2] Exiting...

[Thread1] In Decrementer. Counter: 9.

[Thread1] In Decrementer. Counter: 8.

[Thread1] In Decrementer. Counter: 7.

[Thread1] In Decrementer. Counter: 6.

[Thread1] In Decrementer. Counter: 5.

[Thread1] In Decrementer. Counter: 4.

[Thread1] In Decrementer. Counter: 3.

[Thread1] In Decrementer. Counter: 2.

[Thread1] In Decrementer. Counter: 1.

[Thread1] In Decrementer. Counter: 0.

All my threads are done.

فصل بیست و چهارم ریسما نها و همگام سازی

455

1 آغاز شده و سپس Decrementer) Thead) شروع می شود. در خروجی م یبینید که Decrementer در این مثال ابتدا

1 کارش را آغاز Thread ، 1 را بیدار م ی کند Thread ،2Thread 2 آغاز می شود. فقط زمانی که Thread منتظر می ماند. سپس

می کند.

1 هرگز Thread توضیحات اضافه کنی د . در می یابید که ()Pulse سعی کنید آزمایشاتی روی این کد انجام دهی د . ابتدا به م ت د

هیچ سیگنالی به ریسما نهای منتظر وجود ندارد. ،()Pulse ادامه نمی یابد. بدون

را مجدداً طوری بنویسید که بعد از هر عمل افزایش مانیتور را بیدار کرده و از آن Incrementer ، به عنوان آزمایش دوم

خارج شود.

void Incrementer()

{

try

{

while (counter < 10)

{

Monitor.Enter(this);

long temp = counter;

temp++;

Thread.Sleep(1);

counter = temp;

Console.WriteLine(

"[{0}] In Incrementer. Counter: {1}",

Thread.CurrentThread.Name, counter);

Monitor.Pulse(this);

Monitor.Exit(this);

}

بصورت زیر مجدداً بنویسید. While به یک دستور if را با تغییر دستور Decrementer متد

//if (counter < 10)

while (counter < 5)

Counter را بیدار کن د . زمانی که مقدار Decrementer 2 بعد از هر عمل افزایش، متد Thread این تغییرات باعث م ی شوند

بطور کامل Decrementer ، از 5 بالا رود Counter باید منتظر بماند. زمانی که مقدار Decrementer ، کوچکتر از 5 باشد

می تواند مجدداً اجرا شو د . خروجی بصورت زیر نمایش داده Incrementer اجرا می شود. زمانی که آن اجرا شد، ریسمان

می شود.

[Thread2] In Incrementer. Counter: 2

[Thread1] In Decrementer. Counter: 2. Gotta Wait!

[Thread2] In Incrementer. Counter: 3

[Thread1] In Decrementer. Counter: 3. Gotta Wait!

[Thread2] In Incrementer. Counter: 4

[Thread1] In Decrementer. Counter: 4. Gotta Wait!

[Thread2] In Incrementer. Counter: 5

[Thread1] In Decrementer. Counter: 4.

[Thread1] In Decrementer. Counter: 3.

[Thread1] In Decrementer. Counter: 2.

[Thread1] In Decrementer. Counter: 1.

[Thread1] In Decrementer. Counter: 0.

[Thread2] In Incrementer. Counter: 1

[Thread2] In Incrementer. Counter: 2

[Thread2] In Incrementer. Counter: 3

Mohsen_mahyar@yahoo.com - C# برنامه نویسی

456

[Thread2] In Incrementer. Counter: 4

[Thread2] In Incrementer. Counter: 5

[Thread2] In Incrementer. Counter: 6

[Thread2] In Incrementer. Counter: 7

[Thread2] In Incrementer. Counter: 8

[Thread2] In Incrementer. Counter: 9

[Thread2] In Incrementer. Counter: 10

توجه: در هنگام برنام ه نویسی برای برنام ه های پیچیده بایستی مسائل ب ن بست را در هنگام کاربرد قف ل ها در نظر گرف ت . اگر

باشند، برنامه در بن بست قرار میگیرد. Wait همهی ریسمانها در حالت

-3-20 خلاصه

ریسمانها مسئول چند وظیف هگی یک برنامهی کاربردی واحد هستند.

ریسمان بندی می تواند سرعت اجرای برنامه را پایین بیاورد.

است. Thread • ساده ترین راه ایجاد یک ریسمان، ایجاد یک نمونه جدید از کلاس

زمانی که م ی خواهید به یک ریسمان بگویید تا اجرای کامل ر یسمان دیگر منتظر بماند، ریسمان اول را به ریسمان

دوم پیوند زنید.

را احضار کنید که ریسمان احضار شده را معلق م یسازد. ()Thread.Sleep • می توانید متد ایستای

همگامسازی با یک قفل روی ش ی فراهم می شود.

افزایش و کاهش یک مقدار، یک الگوی برنام ه نویسی عمومی است و آن اغلب به حفاظت از طریق همگا م سازی نیاز

فقط برای این منظور پیشنهاد می کند. Interlocked یک کلاس خاص بنام CLR دارد، که

یک بخش بحرانی از کد را علامتگذاری می کند. ،lock •

یک مانیتور به شما اجازه می دهد تصمیم بگیرید یک همگامسازی کی وارد و کی خارج شود.

مانیتور را آزاد م یکند. ،()Wait • فراخوانی

 

Mohsen_mahyar@yahoo.com - C# برنامه نویسی

 

   + MOHSEN GHASEMI - ۸:۱۱ ‎ب.ظ ; ۱۳۸٩/٤/۳۱

فصل بیست وسوم بانک اطلاعاتی با ADO.NET و SQL SERVER در #C

<!-- /* Font Definitions */ @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:-1610611985 1107304683 0 0 159 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman","serif"; mso-fareast-font-family:"Times New Roman";} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; font-size:10.0pt; mso-ansi-font-size:10.0pt; mso-bidi-font-size:10.0pt;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0; mso-gutter-direction:rtl;} div.Section1 {page:Section1;} -->

فصل بیست و سوم

برنامه نویسی بانک اطلاعاتی با

C#  در ADO.NET و SQL SERVER

آنچه که در این فصل یاد خواهید گرفت:

ADO.NET آشنایی با اشیای

نحوه ی اتصال کنترل ها به داده ها

ADO.NET در DateView بررسی روشهای جستجو و یا مرتب سازی داده های درون حافظه با استفاده از اشیای

آشنا خواهیم ADO.NET با نحوه انتخاب ، درج، ویرایش و یا حذف داد ه های درون یک بانک اطلاعاتی به وسیل ه ی

شد.

SQL Server برنامه نویسی پایگا هداده های تحت

-1-23 مقدمه

در فصل قبلی با بانک اطلاعاتی و برنامه نویسی بانک اطلاعاتی به صورت مقدماتی آشن ا شدیم. توانستیم اطلاعات داخل یک

جدول از بانک اطلاعاتی را در یک برنامه تحت ویندوز بدس ت آورده و آ نها را در جدولی در فرم نمایش دهی م . همچنین بدون

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

در تمام این موارد از یک ویزارد استفاده کردیم و آن ویزارد کدهای زیادی را برای انجام موارد مورد نظر ما نوشت، کدهایی

مخصوص برای جداول مورد DataSet و نیز ایجاد یک DataAdapter مانند ایجاد اتصال به بانک اطلاعاتی، تنظیم کردن

نظر ما . استفاده از این روش برای دسترسی ساده به بانک اطلاعاتی و انجام کارهای معمولی مانند دریافت و مشاهده اطلاعات

از یک یا چند جدول روش مناسبی است ، اما برای نوشتن برنام ه های بزرگتر ، لازم است که کنترل بیشتری بر داد ه ها و یا

کنترل های موجود در برنامه داشته باشیم و این کار نیز فقط از طریق کدنویسی میسر است.

در این فصل سعی خواهیم کرد که نگاه عمی ق تری به مبحث دسترسی به بانک اطلاعاتی داشته باشی م . تکنولوژی هایی که در

فصل قبل برای دسترسی به داد ه ها و یا تغییر در آنها استفاده کردیم ، از قبیل کنترل هایی برای دریافت اطلاعات از بانک

اطلاعاتی،کنترل هایی برای ذخیره آنها در حافظه و نیز کنتر ل هایی برای متصل کردن این داد ه ها به کنتر ل های موجود در فرم ،

mohsen_mahyar@yahoo.com - C# برنامه نویسی

402

ADO.NET شناخته م ی شوند. در این فصل سعی خواهیم کرد با توانای ی ها و قابلیتهای درونی ADO.NET همه مجموعاً به نام

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

درون حافظه ذخیره شده است را تغییر دهیم ، فیلتر کرده و یا DataSet که چگونه م ی توان داده هایی که به وسیله یک

ویرایش کنیم.

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

شوند. بنابراین لازم است که اتصال داد ه ها به کنتر ل ها را نیز دقی ق تر بررسی کنی م . به عبارت دیگر در این فصل مشاهده

خواهیم کرد که چگونه م ی توان کنترل های موجود در فرم را به گون ه ای تنظیم کرد که در هر لحظه فقط داد ه های مربوط به

ها ) و یا چگونه م ی توان با استفاده از اشیایی مانند TextBox یک رکورد را نمایش دهن د (برای مثا ل ، مانند

بین رکوردها حرکت کرد. CurrencyManager

نیز SQL Server در طی این فصل با نحوه ی استفاده از بانک های اطلاعاتی ایجاد شده به وسیله ی موتور بانک اطلاعاتی

به آنها دسترسی پیدا SqlClient آشنا خواهیم شد و خواهیم دید چگونه م ی توان به وسیل ه ی سرویس دهند ه ی اطلاعاتی

که برای کار با بانک اط لا عاتی ) OleDb نسبت به سرویس دهند ه ی اطلاعاتی ،SqlClient کرد. سرویس دهنده ی اطلاعاتی

SQL استفاده می شود) از سرعت بیشتری برخوردار است، اما فقط م یتواند با بانک های اطلاعاتی تحت Access ایجاد شده با

کار کند. Server

SQL 2000 یا SQL Server ،7SQL Server برای انجام تمرینات این فصل لازم است که به یکی از نرم افزارهای

2005 دسترسی داشته باشید. زیرا در برنامه های این فصل از بانک اطلاعاتی نمون های که در این نرم افزارها وجود Server

استفاده شده است. (Pubs دارد (بانک اطلاعاتی

ADO.NET-2-23

NET همانطور که در ابتدای فصل نیز ذکر شد ، به مجموعه کنتر ل هایی که برای دسترسی به داد ه های یک بانک اطلاعاتی در

برای دسترسی به داد ه ها از معماری غیرمتصل استفاده م ی کند .معماری ADO.NET . گفته م ی شود ADO.NET استفاده می شود

غیر متصل به این معنی است که ابتدا برنامه به موتور بانک اطلاعاتی مورد نظر متصل شده ، داده های مورد نیاز خود را از بانک

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

تغییرات مورد نظر خود را در داد ه های موجود در حافظه انجام م ی دهد. هر زمان که لازم باش د ، تغییرات ایجاد شده در بانک

اطلاعاتی ذخیره شوند ، برنامه یک اتصال جدید را به بانک اطلاعاتی ایجاد کرده و از طریق این اتصال تغییراتی را که در

داده ها اعمال کرده بود را در جدول اصلی ایجاد م ی کند. کنترل های اصلی که داد ه های دریافتی از بانک اطلاعاتی را در حافظه

تشکیل DataTable است . این کنترل خود از چند کنترل دیگر مانند اشیایی از نوع DataSet نگهداری می کند،کنترل

مورد نظر خود را SELECT شده است . بعد از اینکه داد ه ها در حافظه قرار گرفتند م ی توانید بین آنها جستجو کنید ، دستورات

روی آنها اجرا کرده و آنها را به این وسیله فیلتر کنید و یا تغییراتی را در این داد ه ها ایجاد کنید که در طی این فصل با

نحوه ی انجام این موارد آشنا خواهیم شد.

استفاده از معماری غی ر متصل مزایای زیادی دارد که مهمترین آن افزایش توانایی برنامه در سرویس دادن به چندین کاربر به

صورت همزمان اس ت . به عبارت دیگ ر ، می توانیم بگوییم با استفاده از این روش م ی توانیم تعداد افرادی که م ی توانند به صورت

همزمان از برنامه استفاده کنند را از د ه ها نفر به صدها نفر افزایش دهی م . دلیل این مورد در این است که در این روش برنام ه ها

فقط در مواقع مورد نیاز به بانک اطلاعاتی متصل م ی شوند و بعد از اجرای وظایف لاز م ، اتصال خود را قطع م یکنند، به این

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

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

403

Data -1 فضای نامی -2-23

قرار م ی گیرند، این فضای نا م ی خود نیز شامل چند فضای نا م ی System.Data در فضای نام ADO.NET کلاس های اصلی

فضای نامی .System.Data.SqlClient و System.Data.OleDb دیگر است که مهمترین آنها عبارتند از

SQL شامل کلاس هایی است که برای دسترسی به بانک های اطلاعاتی ایجاد شده به وسیل هی System.Data.SqlClient

نیز حاوی کلا س هایی است که برای دسترسی به بان ک های System.Data.OleDb به کار م ی رود. فضای نام ی Server

مورد استفاده قرار می گیرد. (Access مانند بانک های اطلاعاتی ) OLE اطلاعاتی از نوع

و System.Data.OracleClient دو فضای نام دیگر وجود دارند که عبارتند از System.Data در فضای نا م ی

برای دسترسی به بانک اطلاعاتی ایجاد شده به وسیل ه ی موتور بانک OracleClient فضای نام ی .System.Data.Odbc

مورد استفاده قرار می گیرد. Oracle اطلاعاتی

برای دسترسی به بان ک های SqlClient کلاس های موجود در این فضای نام نیز ، همانند کلا سهای موجود در فضای نام

نیز حاوی کلا س هایی است که برای دسترسی به بان ک های Odbc بهینه سازی شده اند. فضای نام Oracle اطلاعاتی از نوع

را پشتیبانی نم یکنند ایجاد شده است. OleDB که تکنولوژی ODBC اطلاعاتی قدیمی از نوع

به عنوان سروی س دهنده های اطلاعاتی ADO.NET در Odbc و نیز OracleClient ،OleDb ،SqlCient فضای نامهای

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

سرویس دهنده ی اول تمرکز خواهیم کرد.

دسترسی خواهیم داشت. SQL Server به بانک های اطلاعاتی از نوع SqlClient در طی این فصل با استفاده از فضای نام

استفاده از دیگر سرویس دهند ه های اطلاعاتی نیز بسیار مشابه استفاده از این سرویس دهنده اس ت . ADO.NET البته در

بنابراین به راحتی م ی توانید از تکنیکهایی که با استفاده از کلا س های موجود در این فضای نا م ی خواهید آموخت در سرویس

را در این قسمت به کار OleDB استفاده کنید و یا تکنیکهای سرویس دهند ه هایی مانند OleDB دهنده های دیگر نیز از قبیل

بر اساس نوع موتور بانک اطلاعاتی که داد ه های شما به وسیل ه ی آن ایجاد شد ه اند، یکی از سرویس ADO.NET ببرید. در

دهنده های موجود را انتخاب کرده و از آن استفاده م ی کنید. اما لازم نیست که مجدداً نحو ه ی استفاده از آن سرویس دهنده

را مطالعه کنی د ، زیرا تمامی این سرویس دهند ه ها بسیار مشابه یکدیگر کار م ی کنند و اگر نحو ه ی استفاده از یکی از آنها را

بیاموزید می توانید به راحتی از دیگر سرویس دهند هها نیز استفاده کنید.

کلاس های موجود در این سرویس دهند ه های اطلاعاتی به حدی زیاد هستند که نم ی توانیم تمام آنها را در این قسمت معرفی

کنیم. با این وجود در این قسمت ابتدا با تعدادی از مهمترین آنها که در طی مثا ل های این فصل نیز به کار رفت ه اند آشنا

می شویم.

این کلا سها عبارتند از:

SqlConnection

SqlCommand

SqlDataAdapter

SqlParameter

مورد استفاده قرار م ی گیرند . SQL Server به خاطر داشته باشید که این کلا سها فقط برای ارتباط با بان کهای اطلاعاتی

می توانید از کلاس های متناظر اینها در فضای نا م ی OLEDB برای استفاده از بان ک های اطلاعاتی

به برنامه اضافه کرد تا لازم نباشد هر بار با نام کامل آنها را using را با استفاده از راهنمای System.Data.SqlClient

وارد کنیم. بنابراین به خاطر داشته باشید که در ابتدای برنامه های این قسمت دستور زیر را نیز اضافه کنید:

using System.Data.SqlClient;

را System.Data باید فضای نا م ی DataView و یا DataSet مانند ADO.NET همچنین برای استفاده از کلا س های پایه ای

نیز به برنامه اضافه کنیم. بنابر این در ابتدای برنام ههای خود دستور زیر را نیز وارد کنید.

mohsen_mahyar@yahoo.com - C# برنامه نویسی

404

using System.Data;

داشته باشیم و نحو ه ی کاربرد آنها را SqlClient خوب بهتر است که ابتدا نگاهی به کلا س های اصلی موجود در فضای نام

بررسی کنیم.

:SqlConnection -2 کلاس -2-23

در قلب کلا س هایی قراردارد که در این قسمت مورد استفاده قرار SqlConnection تقریباً می توانیم بگوییم که ک لاس

می دهیم، زیرا این کلاس وظیفه برقراری ارتباط بین برنامه و بانک اطلاعاتی برنامه را بر عهده دار د . هنگامی که بخواهید یک

به آن ارسال کنی د . این پارامتر متغیری از ConnectionString نمونه از این کلاس را ایجاد کنید ، باید پارامتری را به نام

نوع رشته ای است که تمام داد ه های مورد نیاز برای اتصال به یک بانک اطلاعاتی را شامل اس ت . البته بعد از ایجاد شیئی از

در این کلاس مقدار آن را تغییر داده و رشت ه ی ConnectionString این کلاس ، نیز م ی توانیم با استفاده از خاصیت

با استفاده از اطلاعاتی که در کادر VS ، جدیدی را برای این پارامتر مشخص کنی م . در برنامه هایی که در فصل قبل ایجاد کردیم

قرار می داد. اما اغلب بهتر SqlConnection دریافت می کرد، چنین متنی را ایجاد کرده و در اختیار Add Connction

را خودمان بنویسی م . برای این کار ابتدا باید بدانیم که ساختار این مت ن ها ConnectionString است که متن لازم برا ی

باید چگونه باشد.

ring ConnectionSt ایجاد بخش های مختلف

باید مورد استفاده قرار گیر د ، بستگی به سرویس دهند ه ی اطلاعاتی دارد که ConnectionString ساختار متنی که برای

به عنوان موتور بانک اطلاعاتی برنامه خود استفاده SQL Server مورد استفاده قرار می دهیم. برای مثال اگر بخواهیم از

در برنامه استفاده کنی م )، باید مقادیر پارامترهای SqlClient کنیم (به این ترتیب لازم است که از سرویس دهند ه ی

را طبق جدول زیر مشخص کنیم. Database و Server

پارامتر توضیح

نام سرور بانک اطلاعاتی که م ی خواهید از آن استفاده کنید. این پارامتر معمولاً حاوی نام Server

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

بر روی همان کامپیوتری که برنامه را اجرا م ی کند ، نصب شده است ، SQL Server

برای این پارامتر استفاده کنی د . اما ،localhost و ی ا local می توانید از مقادیری مانن د

ای که در کامپیوتر دیگری در شبکه نصب شده است استفاده م یکنید، SQL Server اگر

لازم است که مقدار این پارامتر را برابر با نام آن کامپیوتر در شبکه قرار دهی د . همچنین

قرار داشته باشد، باید بعد از نام کامپیوتر SQL Server اگر در آن کامپیوتر بیش از یک

ای که می خواهید مورد استفاده قرار SQL Server یک علامت \ قرار داده و سپس نام

دهید را ذکر کنید.

نام بانک اطلاعاتی که م ی خواهید مورد استفاده قرار دهید ، در این پارامتر قرار م ی گیرد Database

.(Pubs (برای مثال بانک اطلاعاتی

باید هنگام دسترسی به آنها ابتدا هویت ،SQL Server برای ایجاد امنیت در بان کهای اطلاعاتی ایجاد شده به وسیله ی

مشخص شود. بنابراین اگر بخواهیم توسط یک برنامه به داد ههای موجود در یک بانک SQL Server استفاده کننده توسط

اطلاعاتی دسترسی داشته باشیم، باید اطلاعات لازم برای این تعیین هویت را همراه با دیگر اطلاعات در متن

انجام شود. SQL Server مشخص کنیم. این تعیین هویت به دو روش م یتواند توسط ConnectionString

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

405

روش اول : استفاده از نام کاربری و کلم ه ی عبور لازم برای دسترسی به بانک اطلاعاتی ا س ت که در این صورت باید این دو

قرار دهیم. ConnectionString پارامتر را به صورت مستقیم در متن

روش دوم: استفاده از حساب کاربری است که در ویندوز از آن استفاده م یکنیم.

تعیین هویت شویم، باید پارامترهای نام کاربری و کلم ه ی SQL Server برای اینکه بتوانیم با استفاده از روش اول توسط

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

پارامتر توضیح

این پارامتر باید حاوی نام کاربری باشد که برای اتصال به بانک اطلاعاتی م ی خواهیم از آن User ID

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

ایجاد شده و اجازه ی دسترسی به SQL Server باید یک حساب کاربری به این نام در

داده های مورد نیاز نیز به آن داده شود.

کلمه ی عبوری که برای این نام کاربردی مورد استفاده قرار م یگیرد. Password

می تواند به گون های تنظیم شود که برای تعیین هویت کاربرانی که به آن دسترسی پیدا می کنند SQL Server علاوه بر این

از حساب ویندوزی که با آن وارد کامپیوتر شد ه اند استفاده کن د . در این صورت دیگر نیازی نیست که در متن

Integrated مقادیر نام کاربری و کلم هی عبور را وارد کنید، بلکه فقط باید مشخص کنید که از ConnectionString

نامیده می شود که با استفاده از آن Integrated Security استفاده می کنید(این سیستم به این علت Security

با یکدیگر سعی خواهند که به حداکثر امنیت ممکن در ایجاد یک ارتباط دسترسی پیدا کنند و SQL Server ویندوز و

قرار دهی م ). برای ConnectionString دیگر نیازی نباشد که ن ا م کاربری و کلم ه ی عبور را به صورت مستقیم در متن

قرار true برابر با ConnectionString را در متن Integrated Security استفاده از این سیستم باید مقدار پارامتر

دهید.

به حساب کاربری که برای این فرد در ویندوز SQL Server البته توجه داشته باشید که در این روش نیز باید در محیط

ایجاد شده است ، اجازه ی دسترسی به اطلاعات موجود داده شود ، در غیر این صورت کاربر نم ی تواند به بانک اطلاعاتی متصل

تنظیم م ی شوند، به قطعه ک  د زیر ConnetionString شود. برای اینکه بهتر متوجه شوید که چگونه پارامترهای لازم در

به کار می رود. SqlConnection نگاه کنید. این کد برای ایجاد یک شیئ جدید از نوع

SqlConnection objConnection = new

SqlConnection("Server=localhost;Database=Pubs;User" +" ID=sa;Password=csdotnet;");

به کار م ی رود. مقدار SQL Server برای است ف اده از یک ConnectionString همانطور که مشاهده می کنید این

که می خواهیم از آن استفاده کنیم در کامپیوتری قرار دارد که برنامه SQL در پارامتر مشخص م ی کند که سرور localhost

نیز نام بانک اطلاعاتی که م ی خواهیم به آن متصل شویم را تعیین م ی کند . Database در آن اجرا شده اس ت . مقدار پارامتر

به کار می رود. در آخر نیز مقدار پارامترهای Pubs برای دسترسی به بانک اطلاعاتی ConnectionString در این جا ا ی ن

مشخص می شوند که برای تعیین نام کاربری و کلم هی عبور لازم برای دسترسی به اطلاعات به کار Password و User ID

می روند. دقت کنید که برای تعیین مق د ار هر پارامتر از علامت = و برای جدا کردن پارامترهای مختلف از یکدیگر از علامت ;

استفاده شده است.

متصل شدن و قطع کردن اتصال از یک بانک اطلاعاتی

نحوه ی برقراری ارتباط با بانک اطلاعاتی را مشخص کردی م ، می توانیم با استفاده ا ز ConntionString بعد از اینکه با ایجاد

به بانک اطلاعاتی متصل شده و یا اتصال خود را قطع کنی م . یک نمونه SqlConnection در کلاس Close و Open متدهای

از این کار در قطعه کد زیر نشان داده شده است:

mohsen_mahyar@yahoo.com - C# برنامه نویسی

406

// Open the database connection

objConnection.Open();

// ... Use the connection

objConnection.Close();

// Close the database connection

وجود دارند که م ی توانیم در برنامه از آنها استفاده SqlConnection البته متدها و خاصی ت های فراوان دیگری در کلاس

کنیم، اما مواردی که در اینجا با آنها آشنا شدیم ، پرکاربردترین آنها به شمار م ی روند و فکر م ی کنم که برای شروع فقط

آشنایی با این موارد کافی باشد.

SqlCommand -3 کلاس -2-23

برای اجرا روی داد ه های دریافت شده از بانک اطلاعاتی اس ت . این دستور SQL حاوی یک دستور SqlCommand کلاس

برای درج داد ه های جدید در بانک INSERT برای انتخاب داد ه هایی خاص،یک دستور SELECT می تواند یک دستور

برای حذف داد ه ها از بانک اطلاعات و یا حتی فراخوانی یک پروسیجر ذخیره شده در بانک DELETE اطلاعاتی، یک دستور

ای که در این کلاس نگهداری م یشود می تواند شامل پارامترها نیز باشد. SQL اطلاعاتی باشد. دستور

شده است ، اما س اده ترین آنها برای ایجاد یک شیئ از Overload چندین نسخه SqlCommand از متد سازند ه ی کلاس

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

را نمایش م یدهد: SqlCommand متدهای موجود، آن شی را تنظیم کنید. قطعه کد زیر نحو هی ایجاد یک شی از نوع

SqlCommand objCommand = new SqlCommand();

به تنهایی استفاده نم ی کنند، بلکه آنها را با SqlCommand در برنامه های بانک اطلاعاتی معمولاً از اشیای ایجاد شده از کلاس

و یا ... که در آ ن INSERT،SELECT ها به کار م ی برند. به این ترتیب م ی توانند از دستور DataAdapter ها و DataSet

می توانند به همراه اشیای ایجاد شده SqlCommand نگهداری می شود برای مقاصد مورد نیاز استفاده کنن د . همچنین اشیای

دارد، اما منابع سیستم Dataset کاربردی همانند DataReader مورد استفاده قرار گیرن د . کلاس DataReader از کلاس

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

قرار خواهیم داد. DataSet نحوه ی استفاده از این اشیا با کلاس

Connection خاصیت

استفاده کنیم باید بعضی از خاصی ت های آن را تنظیم کنی م . اولین SqlCommand قبل از اینکه بتوان ی م از یک شی از کلاس

است . این خاصیت همانطور که در قطعه کد زیر نمایش داده شده است ، Connection خاصیتی که باید تنظیم شود ، خاصیت

را دریافت کند: SqlConnection می تواند یک مقدار از نوع

objCommand.Connection = objConnection;

ای که در این شی نگهداری م ی شود را با موفقیت اجرا کرده و نتیج ه ی آن را دریافت کنیم ، SQL برای اینکه بتوانیم دستور

اتصال با بانک اطلاعاتی را برقرار کرده و سپس دستور را اجرا کنیم. SqlConnection در Open ابتدا با استفاده از متد

CommandText خاصیت

است . این خاصیت متنی را دریافت می کند که می تواند حاوی CommandText خاصیت بعدی که باید تنظیم کنیم ، خاصیت

و یا فراخوانی یک پروسیجر ذخیره شده در بانک اطلاعاتی باشد که باید روی داد ه ها اجرا شو د . برای مثا ل ، SQL یک دستور

که در این خاصیت قرار داده شده است را نمایش م یدهد: SQL قطعه کد زیر یک نمونه از دستور

SqlConnection objConnection = new

SqlConnection("Server=localhost;Database=Pubs;User " +

"ID=sa;Password=csdotnet;");

SqlCommand objCommand = new SqlCommand();

objCommand.Connection = objConnection;

objCommand.CommandText = "INSERT INTO authors " +

"(au_id, au_lname, au_fname, contract) " +

"VALUES('123-45-6789', 'Barnes', 'David', 1)";

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

407

است که برای درج یک رکورد از اطلاعات در یک جدول به کار م ی رود. این SQL یکی از دستورات ساده INSERT دستور

au_id ایجاد کن . سپس فیل  د authors دستور در این ق سمت بیان م ی کند که " یک رکورد جدید از اطلاعات در جدول

را برابر با au_fname قرار بده، فیلد Barnes را برابر با au_iname 6789 ' قرار بده، فیلد =45- این رکورد را برابر با ' 123

را نیز برابر با 1 قرار بده ." Contract قرار بده و فیلد 'David'

برای درج یک ردیف از اطلاعات ذر یک جدول ب ه این صورت است که بعد از دستور INSERT روش استفاده از دستور

نام جدولی که م یخواهیم اطلاعات در آن قرار بگیرد را ذکر م یکنیم. سپس نام فیلدهایی را که باید کامل INSERT INTO

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

یک پرانتز دیگر، مقدار مورد نظر برای آن فیلدها را به ترتیب وارد م یکنیم.

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

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

را به گون ه ای ایجاد کنیم که همانند یک متد، پارامتر دریافت کنن د . سپس SQL می شوند. خوشبختانه می توانیم دستورات

هنگام اجرای برنامه این پارامترها را از کاربر دریافت کرده و آنها را در دستور قرار م ی دهیم و دستور را اجرا م ی کنیم . بهتر

قرار گیرند آشنا شویم. SqlCommand است مقداری هم با پارامترهایی که می توانند در شی

Parameters خاصیت

را ارائه کنیم، باید با مفهوم جاگیرنده 1ها آشنا شوید که SQL قبل از اینکه بتوانیم نحو ه ی استفاده از پارامترها در یک دستور

قرار م ی گیرند و م ی توانند در زمان اجرای برنامه جای خود را با عباراتی خاص SQL متغیرهایی هستند که در یک دستور

استفاده SQL عوض کنند . این متغیرها با علامت @در یک دستور مشخص م ی شوند و هنگامی که از آنها در یک دستور

کنیم، قبل از اجرای دستور باید تمامی آنها را با مقادیر مناسب تعویض کنی م . برای م ثال، اگر بخواهیم در دستور قبل مقادیر

را در زمان اجرای برنامه مشخص کنیم، باید جای آنها را با چهار جاگیرنده به INSERT از دستور VALUES لازم برای قسمت

صورت زیر عمل کنیم:

همانطور که مشاهده م ی کنید در اینجا به جای اینکه از چند مقدار ثابت ذر ذستور استفاده کنیم، از چند جاگیرنده استفاده

کرده ایم. همچنین جاگیرنده ها در دستورها با استفاده از @ مشخص شد ه اند. البته هیچ ضرورتی ندارد که نام یک جاگیرنده

همنام فیلدی باشد که قرا ر است مقدار جاگیرنده در آ ن قرار بگیر د . اما این کار باعث م ی شود که برنامه خواناتر شده و درک

آن ساده تر باشد.

SqlConnection objConnection = new

SqlConnection("Server=localhost;Database=Pubs;User " +

"ID=sa;Password=csdotnet;");

SqlCommand objCommand = new SqlCommand();

objCommand.Connection = objConnection;

objCommand.CommandText = "INSERT INTO authors " +

"(au_id, au_lname, au_fname, contract) " +

"VALUES(@au_id, @au_lname, @au_fname, @au_contract)";

این جاگیرنده ها را SQL خوب، بعد از اینکه با استفاده از این روش پارامترهای ی را در دستور ایجاد کردیم ، باید قبل از دستور

با مقادیر مناسب تعویض کنی م . این کا ر به صورت اتوماتیک توسط برنامه در زمان اجرای دستور انجام م ی شود. اما ابتدا باید

قرار م ی دهیم تا SqlCommand در شیئایجاد شده از کلاس Paramaters پارامترهایی را ایجاد کرده و آن را در لیست

برنامه بداند هنگام اجرای دستور هر جاگیرنده را باید با مقدار چه متغیری د ر برنامه عوض کن د . توجه کنید که اصطلاح پارامتر

1 PlaceHolder

mohsen_mahyar@yahoo.com - C# برنامه نویسی

408

و یا پروسیجر ذخیره شده در بانک اطلاعاتی SQL در این قسمت به پارامترهایی اشاره م ی کند که برای اجرای یک دستور

به متدها فرستاده می شود. #C لازم است، نه به پارامترهایی که در ویژوال

Parameters وجود دارد م ی توانیم از خاصیت SqlCommand برای دسترسی به لیست پارامترهایی ک ه در یک شی از کلاس

در این کلاس استفاده کنی م . این خاصیت حاوی لیستی از جاگیرنده ها به همراه متغیرهای وابسته به آنها اس ت . بنابراین در

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

ساده ترین روش انجام این کار در کد زیر نشان داده شده است.

SqlConnection objConnection = new

SqlConnection("Server=localhost;Database=Pubs;User

ID=sa;Password=csdotnet;");

SqlCommand objCommand = new SqlCommand();

objCommand.Connection = objConnection;

objCommand.CommandText = "INSERT INTO authors " +

"(au_id, au_lname, au_fname, contract) " +

"VALUES(@au_id, @au_lname, @au_fname, @au_contract)";

objCommand.Parameters.AddWithValue("@au_id",

txtAuId.Text);

objCommand.Parameters.AddWithValue("@au_lname",

txtLastName.Text);

objCommand.Parameters.AddWithValue("@au_fname",

txtFirstName.Text);

objCommand.Parameters.AddWithValue("@au_contract",

chkContract.Checked);

نام یک جاگیرنده و متغیری که مقدار مربوط به آن را در زمان اجرای برنامه نگهداری م ی کند را به AddWithValue متد

اضافه م ی کند. برای مثال ، در این قسمت مشخص کرد ه ایم که Parameters عنوان پارامتر دریافت کرده و آن را به لیست

عوض شو د . همچنین txtAuId کنترل Text باید با مقدار خاصیت au_id@ هنگام اجرای دستور ، مکان جاگیرنده با نام

عوض شود و ... txtLastName مربوط به کنترل Text نیز با مقدار خاصیت au_lName@ مکان جاگیرنده با نام

ExecuteNonQuery متد

بعد از انجام تمام این مراحل م ی توانید دستور موجود در این شی را روی داد ه های بانک اطلاعاتی اجرا کنید. برای این کار

دستور موجود در شی ExecuteNonQuery ابتدا باید اتصال خود را ب ه بانک اطلاعاتی برقرار کنید. سپس با فراخوانی متد

را اجرا کنی د . البته این متد همانطور که نام آن نیز مشخص م ی کند فقط زمانی کاربرد دارد که بخواهیم SqlCommand

SqlCommand دستوری را روی بانک اطلاعاتی اجرا کنیم که داد ه ای را بر نم ی گرداند. برای مثال ، اگر دستور موجود در ش ی

باشد که اطلاعاتی را از جدول استخراج کرده و آنها را به برنامه دهد، نم ی توانیم برای اجرای آن از این SELECT یک دستور

متد استفاده کنی م . اما اگر دستور مورد استفاده فقط تغییراتی را در داد ه های بانک اطلاعاتی ایجاد کند ( برای مثا ل ، یک

رکورد از اطلاعات را به جدول اضافه کند) می توانیم با فراخوانی آن متد دستور را در بانک اطلاعاتی اجرا کنیم.

این متد بعد از اجر ا، عددی را به عنوان خروجی بر م ی گرداند که مشخص کنند ه ی تعداد رکوردهایی است که با اجرای این

تغییر کرده اند. این عدد معمولاً برای بررسی صحت اجرای دستور مورد استفاده قرار م ی گیرد . قطعه کد زیر SQL دستور

را در برنامه نشان می دهد. ExecuteNonQuery نحوه ی استفاده از دستور

SqlConnection objConnection = new

SqlConnection("Server=localhost;Database=Pubs;User

ID=sa;Password=csdotnet;");

SqlCommand objCommand = new SqlCommand();

objCommand.Connection = objConnection;

objCommand.CommandText = "INSERT INTO authors " +

"(au_id, au_lname, au_fname, contract) " +

"VALUES(@au_id, @au_lname, @au_fname, @au_contract)";

objCommand.Parameters.AddWithValue("@au_id",

txtAuId.Text);

objCommand.Parameters.AddWithValue("@au_lname",

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

409

txtLastName.Text);

objCommand.Parameters.AddWithValue("@au_fname",

txtFirstName.Text);

objCommand.Parameters.AddWithValue("@au_contract",

chkContract.Checked);

objConnection.Open();

objCommand.ExecuteNonQuery();

objConnection.Close();

SqlDataAdapter -4 کلاس -2-23

در برنام ه های بانک اطلاعاتی ، همانند پلی بین جداول بانک اطلاعاتی و نیز داد ه های موجود در حافظه DataAdapter کلاس

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

ی که به آن نسبت داده م ی شود استفاده م ی کند و همانطور که م ی دانید، هر شی از کلاس SqlCommand کلاس

است که ارتباط آن را با بانک اطلاعاتی برقرار م ی کند . بنابراین SqlConnection حاوی شیئی از کلاس SqlCommand

SqlConnection و SqlCommand برای دسترسی به بانک اطلاعاتی از کلاس DatAdapter می توانیم بگوئیم که کلاس

استفاده می کند.

است که از دستور موجود در آن شیئ برای دریافت SelectCommand دارای خاصیتی به نام DataAdapter کلاس

دستوری که در این خاصیت DataAdapter ، داده های مورد نیاز برنامه از بانک اطلاعاتی ب ه کار م ی رود. به عبارت دیگ ر

قرار DataTable و یا DataSet نگهداری می شود را روی بانک اطلاعاتی اجرا کرده و نتایج آن را در کلا س هایی مانند

دارای خاص  یت هایی به نام Datadapter می دهد تا در برنام ه ها مورد استفاده قرار گیرن د . علاوه بر این کلاس

را قبول SqlCommand است که هر یک شی ئ ی از نوع UpdateCommand و InsertCommand ،DeleteCommand

از دستور ذخیره شده در هر یک از آنها به ترتیب برای حذف ،درج و یا ویرایش داد ه ها در بانک DataAdapter می کنند و

اطلاعاتی استفاده م ی کند. در حقیقت هنگامی ک ه ما در طی برنامه ت غ ییراتی را در درون داد ه های موجود در حافظه نگهداری

با استفاده از دستورات موجود در این خاصی ت ها تغ ییرات ما را از داد ه های حافظه به داد ه های DataAdapter ، می کنیم

موجود در بانک اطلا عاتی منتقل م ی کند. ممکن است ابتدا این موارد کمی پیچیده به نظر برسند، اما استفاده از آنها مانند

تمام قسمتهای دیگری که تاکنون مشاهده کرد ه ایم ساده هستن د . در قسم ت های قبل مشاهده کردید که چگونه م ی توان

مورد نیاز را برای انتخاب داد ه ها از بانک اطلاعاتی ایجاد کر د . برای تکمیل دستورات مورد نیاز برای کلاس SELECT دستورات

کلاسی به نام VS مورد نظر خود را وارد کنید. در SELECT نیز فقط کافی است که دستور DataAdapter

و یا UPDATE،INSERT وارد شده، دستورات SELECT وجود دارد که می تواند بر اساس دستور CommandBuilder

و نحوه ی استفاده از آن را برسی SelectCommand مناسب تولید کن د . بنابراین بهتر است که ابتدا با هم خاصیت DELETE

دستورات دیگر را نیز تولید کرد. CommandBuilder کنیم. سپس مشاهده خواهیم کرد که چگونه می توان با استفاده از

SelectCommand خاصیت

برای دریافت DataAdapter در کلاس SelectCommand 1 نیز نشان داده شده است، خاصیت - همانطور که در شکل 23

به کار می رود. DataSet داده های مورد نیاز در برنامه از بانک اطلاعاتی و قرار دادن آنها در

1- شکل 23

mohsen_mahyar@yahoo.com - C# برنامه نویسی

410

اطلاعات مورد نیاز را از یک بانک اطلاعاتی دریافت کنید ، ابتدا باید DataAdapter هنگامی که بخواهید با استفاده از کلاس

دریافت کرده که SqlCommand تنظیم کنید . این خاصیت شی ئ ی از نوع DataAdapter را در SelectCommand خاصیت

این ش ی مشخص م ی کند داد ه ها چگونه باید از بانک اطلاعاتی انتخاب و نیز چه داد ه هایی باید انتخاب شون د . اشیایی که از

ایجاد م ی شوند، همانطورکه در قسمت قبلی مشاهده کردید خود خاصی ت هایی د ارند که قبل از استفاده SqlCommand کلاس

باید آنها را تنظیم کرد. این خاصیت عبارتند از:

در این قسمت قرار گرفته و نحو ه ی اتصال به بانک اطلاعاتی SqlConnection یک شیی از کلاس :Connection •

را مشخص می کند.

و یا نام پروسیجر ذخیره شده در بانک اطلاعاتی که باید ت وسط شی اجرا شود ، در این SQL دستور :CommandText •

قسمت ذخیره می شود.

استفاده کردی م . اما اگر SqlCommand از کلاس CommandText مشخص در خاصیت SQL در قسمت قبل از یک دستور

بخواهیم نام یک پروسیجر ذخیره شده در بانک اطلاعاتی را در این خاصیت قرار دهیم تا اجرا شود ، باید خاصیت دیگری به

قرار دهیم تا StoredProcedure تنظیم کرده و مقدار آن را برابر با SqlCommand را نیز در کلاس CommandType نام

البته در این فصل فقط .SQL نام یک پروسیجر ذخیره شده است ، نه یک دستور CommandText مشخص شود که متن درون

را تغییر CommandType استفاده م ی کنیم، بنابراین نیازی نیست که خاصیت CommandText در خاصیت SQL از دستورات

داده و برابر با مقدار خاصی قرار دهیم.

SQL با استفاده از دستور SelectCommand تنظیم خاصیت

به وسیل ه ی کلاس SQL قطعه کدی که در زیر آورده شده است نحو ه ی تنظیم خاصی ت های مورد نیاز برای اجرای یک دستور

را نمایش می دهد: DataAdapter

// Declare a SqlDataAdapter object...

SqlDataAdapter objDataAdapter = new SqlDataAdapter();

// Assign a new SqlCommand to the SelectCommand property

objDataAdapter.SelectCommand = new SqlCommand();

// Set the SelectCommand properties...

objDataAdapter.SelectCommand.Connection = objConnection;

objDataAdapter.SelectCommand.CommandText =

"SELECT au_lname, au_fname FROM authors " +

"ORDER BY au_lname, au_fname";

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

411

ایج اد کنیم . سپس باید SqlDataAdapter اولین کاری که باید در این قسمت انجام دهیم این است که شی ئ ی را از نوع

را به آن SqlCommand آن را تنظیم کنی م . برای تنظیم این خاصیت باید یک شیئ از کلاس SelectCommand خاصیت

آن را انجام م ی دهیم تا بتواند به Connection نسبت دهیم، بنابراین شیئی را از این کلاس ایجاد کرده و تنظیمات مربوط به

قرار م ی دهیم تا آن را SQL آن را نیز برابر با یک دستور CommandText یک بانک اطلاعاتی متصل شو د . در آخر نیز خاصیت

روی بانک اطلاعاتی اجرا کرده و نتیجه را دریافت کند.

با استفاده از پروسیجر ذخیره شده SelectCommand تنظیم خاصیت

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

است که SQL تنظیم کرد . همانطور که در قسمت قبلی نیز گف ت ه شد ، یک پروسیجر ذخیره شده ، یک مجموعه از دستورات

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

آن را ،SQL در بانک اطلاعاتی وجود دارد که م ی خواهیم به جای استفاده از دستور usp_select پروسیجری به نام

فراخوانی کرده و نتایج اجرای آن را دریافت کنیم. قطعه کد زیر نحو هی انجام این کار را نمایش م یدهد:

// Declare a SqlDataAdapter object...

SqlDataAdapter objDataAdapter = new SqlDataAdapter();

// Assign a new SqlCommand to the SelectCommand property

objDataAdapter.SelectCommand = new SqlCommand();

// Set the SelectCommand properties...

objDataAdapter.SelectCommand.Connection = objConnection;

objDataAdapter.SelectCommand.CommandText = "usp_select";

objDataAdapter.SelectCommand.CommandType =

CommandType.StoredProcedure;

CommandText را در خاصیت SQL همانطور که مشاهده م ی کنید در این قطعه برنامه ، برخلاف قسمت قبل که یک دستور

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

برای تعیین نوع متن موجود در این خاصیت ، باید .SQL نام یک پروسیجر ذخیره شده است، نه یک دستور CommandText

است که مشخص CommandType.Text استفاده کنی م . مقدار پیش فرض این خاصیت برابر با CommandType از خاصیت

است. در این قطعه کد، این مقدار را تغییر داده و برابر با SQL می کند م تن موجود یک دستور

نام یک CommandText قرار م ی دهیم تا مشخص شود مقدار موجود در خاصیت CommandType.StoredProcedure

پروسیجر ذخیره شده است.

دیگر SQL برای ایجاد دستورات CommandBuilder استفاده از

می توانیم داده های مورد نیاز در برنامه را از بانک DataAdapter موجود در کلاس SelectCommand با استف اده از خاصیت

در حافظه قرار دهی م . سپس در طول برنامه م ی توانیم به کاربر اجازه دهیم تا DataSet اطلاعاتی استخراج کرده و در یک

تغییرات مورد نظر خود را در داد ه های موجود د ر حافظه ایجاد کرده و بعد از اتمام آنها، این تغییرات را به داد ههای موجود در

مورد نیاز برای درج ، حذف و یا ویرایش داد ه های دریافتی را به SQL بانک منعکس کنی م . برای این کار لازم است که دستورات

اضافه کنیم تا این کلاس بتواند با استفاده از این دس ت ورات، تغییرات ایجاد شده را در بانک اطلاعاتی DataAdapter کلاس

وارد کند.

تسلط بیشتری داشته باشیم. خوشبختانه روش ساده تری هم برای SQL اما برای ایجاد این دستورات لازم است که به زبان

که برای SELECT است که م ی تواند با توجه به دستور CommandBuilder انجام این کار وجود دارد و آن استفاده از کلاس

مناسب تولید کن د . قطعه کد زیر نحو ه ی استفاده DELETE و نیز UPDATE ،INSERT وارد کرد ه ایم، دستورات DataAdapter

از این دستورات را نمایش م یدهد.

// Declare a SqlDataAdapter object...

SqlDataAdapter objDataAdapter = new SqlDataAdapter();

// Assign a new SqlCommand to the SelectCommand property

objDataAdapter.SelectCommand = new SqlCommand();

mohsen_mahyar@yahoo.com - C# برنامه نویسی

412

// Set the SelectCommand properties...

objDataAdapter.SelectCommand.Connection = objConnection;

objDataAdapter.SelectCommand.CommandText = "usp_select";

objDataAdapter.SelectCommand.CommandType =

CommandType.StoredProcedure;

// automatically create update/delete/insert commands

SqlCommandBuilder objCommandBuilder =

new SqlCommandBuilder(objDataAdapter);

به بانک اطلاعاتی به صورت DataSet با استفاده از این کلاس ، دستورات لازم برای منعکس کردن تغییرات ایجاد شده از

اتوماتیک نوشته م ی شود. در ادامه ی فصل با نحو ه ی انجام این کار بیشتر آشنا خواهیم شد، اما فعلا بهتر است ببینیم که

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

Fill متد

را در بانک SelectCommand موجود در خاصیت SQL می توانید دستور DataAdapter در کلاس Fill با استفاده از متد

در حافظه قرار دهی د . البته قبل DataSet اطلاعاتی اجرا کرده ، و سپس داد ه های برگشتی از اجرای این دستور را درون یک

ایجاد کنیم. DataSet از استفاده از این متد، باید شیئی از نوع

// Declare a SqlDataAdapter object...

SqlDataAdapter objDataAdapter = new SqlDataAdapter();

// Assign a new SqlCommand to the SelectCommand property

objDataAdapter.SelectCommand = new SqlCommand();

// Set the SelectCommand properties...

objDataAdapter.SelectCommand.Connection = objConnection;

objDataAdapter.SelectCommand.CommandText = "usp_select";

objDataAdapter.SelectCommand.CommandType =

CommandType.StoredProcedure;

DataSet objDataSet = new DataSet();

داده ها ی Fill مورد نیاز را ایجاد کردیم ، می توانیم با استفاده از متد DataAdapter و نیز DataSet حال که یک شی

نیز همانند بسیاری از متدهای دیگر دارای نسخ ه های گوناگونی است ، Fill قرار دهی م . متد DataSet بانک اطلاعاتی ر ا در

اما یکی از پرکاربردترین آنها به صورت زیر مورد استفاده قرار می گیرد:

SqlDataAdapter.Fill(DataSet, String);

String ای است که باید داد ه ها در آن قرار بگیرن د . پارامتر DataSet در این متد مشخص کنند ه ی نام DataSet پارامتر

ها نیز م ی توانند همانند بان ک های DataSet . نیز نام جدولی را مشخص م ی کند که داد ه ها در آن جدول قرار م ی گیرند

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

مشخص کنیم که نام جدولی که داد ه ها در آن قرار م ی گیرند چه باید باشد؟ در اینجا م ی توانیم هر نام که تمایل داشته باشیم

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

درک برنامه بسیار راحت تر خواهد بود.

در Fill قطعه کد زیر یک پروسیجر ذخیره شده در بانک اطلاعاتی را اجرا کرده و نتایج برگشتی از آن را به وسیل ه ی متد

قرار می دهد: ObjDataSet در authors جدولی به نام

// Declare a SqlDataAdapter object...

SqlDataAdapter objDataAdapter = new SqlDataAdapter();

// Create an instance of a new select command object

objDataAdapter.SelectCommand = new SqlCommand();

// Set the SelectCommand properties...

objDataAdapter.SelectCommand.Connection = objConnection;

objDataAdapter.SelectCommand.CommandText = "usp_select";

objDataAdapter.SelectCommand.CommandType =

CommandType.StoredProcedure;

DataSet objDataSet = new DataSet();

// Fill the DataSet object with data...

objDataAdapter.Fill(objDataSet, "authors");

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

413

قرار دارد استفاده SelectCommand ای که در خاصی ت Connection برای اتصال به بانک اطلاعاتی از شی Fill متد

به بانک اطلاعاتی برقرار است یا ن ه . در صورتی که اتصال Connection می کند. این متد ابتدا بررسی م ی کند که این اتصال

با بانک اطلاعاتی را Connection داده های مورد نیاز را از بانک اطلاعاتی بدست آورده ، اما اتصال Fill برقرار باشد، متد

ارتباط را Open با فراخوانی متد Fill با بانک اطلاعاتی قطع باشد، متد Connection قطع نمی کند. اگر هم ارتباط ش ی

را فراخوانی م ی کند تا اتصال به بانک اطلاعاتی مجدداً Close برقرار کرده و پس از بدست آو ر دن اطلاعات مورد نیاز ، متد

قطع شود.

به این ترتیب داد ه ها از بانک اطلاعاتی درون حافظه قرار م ی گیرند و م ی توانید به صورت مستقل آنها را تغییر دهی د . دقت

وجود ندار د . دلیل این مورد هم این است که این کلاس متعلق به فضای نام Sql کلمه ی DataSet کنید که ابتدای کلاس

به Dataset قرار دار د . به عبارت دیگ ر ، کلاس System.Data نیست بلکه در فضای نام System.Data.SqlClient

ت علق ندارد و وظیف ه ی آن نگهداری اطلاعات به دس ت OleDb یا SqlClient سرویس دهند ه ی اطلاعاتی خاصی از قبیل

آمده ( به هر نحوی ) در حافظه اس ت . هنگامی که اطلاعات را در حا ف ظه قرار دادیم دیگر نیازی نیست بدانیم که این اطلاعات

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

DataSet -5 کلاس -2-23

بر ای تگهداری اطلاعات به دست آمده از بانک اطلاعاتی در حافظه به کار م ی رود. این DataSet همانطور که گفتم کلاس

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

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

پرس وجوهایی را روی داد ه های DataView کرده و به کاربر اجازه دهد که آنها را ویرایش کن د . همچنین با استفاده از کلاس

موجود در آن اجرا کرد.

داده هایی که در این کنترل قرار دارند از بانک اطلاعاتی قطع هستن د ، ارتباطی با بانک ندارند . در طول برنامه م ی توانیم

داده های موجود در آن را حذف کرده، ویرایش یا اضافه کنیم و بعد از اتمام تغییرات مورد نظر ، مجدداً با استفاده از

به بانک اطلاعاتی متصل شده و تغییرات را در بانک اطلاعاتی ذخیره کنیم. DataAdapter

برای ذ خ یره داده ها استفاده م ی کند. به این ترتیب م ی توانید داد ه های موجود در یک شیئ از XML از ساختار DataSet کلاس

را به سادگی در یک فایل ذخیره کرده و یا آن را با استفاده از شبکه به کامپیوتر دیگری منتقل کنی د . البته DataSet کلاس

رفتار کنی د . بلکه کافی است تمام کارهای مورد نظر XML لازم نیست با آنها در قالب DataSet هنگام برنامه نویسی و کار با

کنترل خواهد DataSet انجام دهید، بقیه ی امور را کلاس DataSet خود را با استفاده از خاصی ت ها و یا متدهای موجود در

کرد.

را شرح XML نیز دارای یک الگو است (فایلی که ساختار داده های درون یک یا چند فایل DataSet یک ،XML مانند هر سند

ایجاد XSD را به برنامه اضافه کردیم، فایلی با پسوند DataSet می دهد). در فصل قبل هنگامی که با استفاده از ویزارد یک

. ( 2- در آن قرار گرفت(شکل 23 DataSet شد و الگوی

mohsen_mahyar@yahoo.com - C# برنامه نویسی

414

2- شکل 23

به وسیل ه ی این فای ل ، VS . نگهداری م ی شد CustomerDataSet اطلاعاتی بود که به وسیل ه ی XML این فایل حاوی الگوی

مشتق م ی کند تا بتواند داد ه های دریافت شده از بانک اطلاعاتی را در شی ئ ی از آن کلاس DataSet کلاسی را از کلاس

انجام می شود. DataSet نگهداری کند. البته تمام این موارد نیز از دید برنام هنویس دور می ماند و به صورت درونی توسط

را به کنتر ل های درون فرم متصل کنیم ، تا آن کنتر ل ها داده های DataSet همچنین می توانیم فیلدهای درون یک جدول از

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

این مورد صحبت خواهیم کرد.

DataView -6 کلاس -2-23

عموماً برای جستجو، مرتب کردن، فیلترکردن، ویرایش کردن و یا حرکت کردن در بین داد ه های درون DataView کلاس

یک کنترل قابل اتصال است، یعنی همانطور که م ی توان DataView مورد استفاده قرار م ی گیرد. کنترل DataSet یک

نیز متصل کر د . در این مورد در ادامه فصل DataView متصل کرد، می توان آنها را به یک DataSet کنترل ها را به یک

بیشتر صحبت خواهیم کرد.

می تواند شامل چندین جدول باشد که هر یک از آنها به وسیل ه ی یک کنترل DataSet همانطور که گف ت یم یک کنترل

قرار DataSet داده هایی را درون یک DataAdapter مشخص می شود. در حقیقت هنگامی که با استفاده از DataTable

و سپس داد ه ها را درون آن قرار ( DataTable می دهید، ابتدا یک جدول جدید ایجاد کرده (یک شیئ جدید از نوع

انجام م ی دهد این است که به شما اجازه م ی دهد به DataView اضافه م ی کنید. کاری که کنترل DataSet می دهید و به

نگاه کن ی د. برای مثا ل ، آنها را به صورت مرتب شده مشاهده DataSet صورتی که تمایل دارید به داد ه های یکی از جداول

خاصی را روی جداول اجرا کرده و نتایج را ببینی د . می توانید یک شی SQL می کنید و یا همانند یک بانک اطلاعاتی ، دستورات

باشد و فقط نحو ه ی DataSet را به گون ه ای ایجاد ک ن ید که تمامی داد ه های موجود در یک جدول از DataView از کلاس

LastName وجود داشته باشد که براساس DataSet در authors نمایش آنها را تغییر دهی د . برای مثال ، اگر جدولی به نام

را به گون ه ای ایجاد کنید که حاوی همان اطلاعا ت باشد، اما آنها را ابتدا براساس DataView مرتب شده است ، می توانید یک

از LastName ایجاد کنید که فقط فیلد DataView مرتب کند و یا حتی م ی توانید یک LastName و سپس FirstName

را نمایش دهد و . . . FirstName را نمایش دهد و یا فقط فیلد authors جدول

را به گون ه ای دیگر مشاهده DataTable اطلاعات درون یک DataView البته با وجود اینکه م ی توانید به وسیل ه ی کلاس

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

باید نام جدولی که م ی خواهیم به آن متصل شود را در متد سازند ه ی آن مشخص ،DataView برای ایجا یک ش ی از کلاس

متصل م ی شود . ObjDataSet از authors ایجاد شده و به جدول DataView کنیم. در قطعه ک د زیر، یک شی از کلاس

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

415

به همراه نام جدول مورد نظر DataSet در کلاس Tables دقت کنید که برای دسترسی به یک جدول خاص از خاصیت

استفاده کرده ایم.

// Set the DataView object to the DataSet object...

DataView objDataView = new

DataView(objDataSet.Tables("authors"));

Sort خاصیت

متصل کردید، م ی توانید نحو ه ی DataSet ایجاد کرده و آن را به یک جدول درون DataView هنگامی که یک شی از نوع

نمایش داده ها را تغییر دهی د . برای مثال تصور کنید که م ی خواهید داده های درون جدول را به گون ه ای متفاوت مرتب کنی د .

استفاده کرده و مقدار آن را برابر با نام ستون و یا ستو ن هایی DataView در کلاس Sort برای این کار م ی توانید از خاصیت

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

مرتب می کند: LastName و FirstName در قسمت قبل ایجاد کردیم، براساس

objDataView.Sort = "au_fname, au_lname";

ORDER BY همانطور که مشاهده می کنید عبارتی که به این خاصیت نسبت داده م یشود، همانند عبارتی است که در مقابل

تمام مرت ب سازی ها به طور ،SELECT وارد م ی کردیم. در این قسمت نیز همانند دستور SQL زبان SELECT در دستور

پیش فرض به صورت صعودی انجام م ی شوند و برای اینکه بتوانیم ترتیب مرتب شدن آنها را به نزولی تغییر دهیم ، باید در

را براساس authors استفاده کنی م . برای مثال ، قطعه کد زیر ، داده های موجود در جدول DESC مقابل نام ستون از عبارت

به صورت نزولی مرتب می کند: lastName به صورت صعودی و فیلد FirstName فیلد

objDataView.Sort = "au_fname,au_lname DESC";

RowFilter خاصیت

می توانید داده های موجود در یک جدول را فیلتر کن ی د، به گونه ای که DataView علاوه بر مرتب کردن داد ه ها، با استفاده از

در SELECT از دستور WHERE فقط داده هایی که دارای شرایط خاصی هستند نمایش داده شون د . این امکان همانند قسمت

است که شرط خاصی را برای نمایش داده شدن داد ه ها ایجاد می کرد. برای فیلتر کردن اطلاعات نیز م ی توانید از SQL زبان

استفاده کرده و شرط موردنظر خود را در آن قرار دهی د . نحوه ی وارد کردن دستورات در این قسمت RowFilter خاصیت

است . فقط توجه داشته باشید ، به علت اینکه کل عبارت SELECT از ذستور WHERE نیز همانند وارد کردن شر ط ها در قسمت

شرط باید درون علامت " قرار بگیرند، پس اگر بخواهید رشت ه ای را در شرط م شخص کنید باید آن را درون علامت ' قرار

است نمایش م یدهد: Green آنها برابر با LastName فقط افرادی را که authors دهید. برای مثال، قطعه کد زیر در جدول

// Set the DataView object to the DataSet object...

DataView objDataView = new

DataView(objDataSet.Tables("authors"));

objDataView.RowFilter = "au_lname = 'Green'";

است را بر می گرداند: Green آنها مخالف LastName افرادی که authors و یا قطعه کد زیر در جدول

// Set the DataView object to the DataSet object...

DataView objDataView = new

DataView(objDataSet.Tables("authors"));

objDataView.RowFilter = "au_lname <> 'Green'";

چندین شرط را با یکدیگر OR یا AND به علاوه در شزطی که در این قسمت وارد م ی کنید می توانید با استفاده از عبارات

افرادی را authors ترکیب کرده و سپس داد ه ها را بر اسا س شرط نهایی نمایش دهی د . برای مثال ، قطعه کد زیر در جدول

باشد: Green آنها نیز برابر با LastName شروع شده و D آنها با حرف FirstName نمایش می دهد که

objDataView.RowFilter =

"au_lname <> 'Green' AND au_fname LIKE 'D*'";

mohsen_mahyar@yahoo.com - C# برنامه نویسی

416

Find متد

استفاده کنی د . DataView در کلاس Find برای پیدا کردن یک رکورد خاص از اطلاعات در بانک اطلاعات ی ، می توانید از متد

البته قبل از فراخوانی این متد ، باید داد ه های جدول را بر حسب فیلدی که م ی خواهید جستجو را براساس آن انجام دهید

باید داد ههای موجود در جدول را براساس ستونی که حاوی ک ل ید ،Find مرتب کنید . به عبارت دیگر قبل از فراخوانی متد

مورد نظر شماست مرتب کنید.

به authors که در قسمت قبل ایجاد کردیم، در جدول ObjDataView برای مثال ، تصور کنید که م ی خواهید با استفاده از

au_fname باشد . برای این کا ر ، ابتدا باید جدول را براساس فیلد Ann آن برابر با FirstName دنبال رکوردی بگردید که

بگردید. قطعه کد زیر روش انجام این کار را نمایش م یدهد: Ann به دنبال Find مرتب کنید، سپس با استفاده از متد

int intPosition;

objDataView.Sort = "au_fname";

intPosition = objDataView.Find("Ann");

باشد و شمار ه ی مکان آن را بر Ann آن برابر با FirstName در جدول به نام فردی م ی گردد که DataView به این ترتیب

اولین Find می گرداند. اگر چنین فردی در جدول پیدا نشد ، این مقدار تهی را بر م ی گرداند. دقت کنید به محض اینکه متد

گزینه را پیدا کرد ، مکان آن را برگردانده و از جستجوی ادام ه ی جدول صرفنظر می کند، بنابراین اگر می دانید که بیش از یک

فرد با این نام در جدول وجود دارد برای مشاهده تمام آنها می توانید از روش فیلتر کردن که توضیح داده شد استفاده کنید.

و یا . . باشد را برم یگرداند. ANN و یا Ann همجنین این متد به کوچکی و یا بزرگی حروف حساس نیست و هر فردی که نام او

البته دقت کنید که ا ی ن متد دقیقاً به دنبال متنی که وارد شده است برم ی گردد. بنابراین باید تمام کلمه و یا کلماتی که

می خواهید جستجو براساس آن انجام گیرد را به صورت دقیق در این قسمت وارد کنی د . برای مثال ، اگر م ی خواهید در جدول

بفرستید و انتظار Find را به عنوان پارامتر به متد Del بگردید، نمی توانید Del Castillo به دنبال فردی با نام خانوادگی

داشته باشید که این نام را برای شما برگرداند. بلکه باید نام کامل او را در این قسمت وارد کنید، همانند دستور زیر:

objDataView.Sort = "au_lname";

intPosition = objDataView.Find("del castillo");

می توان یک جدول را براساس چند فیلد مرتب کر د . همین مورد DataView در قسمت قب ل مشاهده کردید که با استفاده از

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

ایجاد م ی کنید و سپس مقدار مورد نظر برای هر ستون را در آن قرار Object کار، بعد از مرتب کردن جدول ، آرایه ای از نوع

می فرستید. برای مثال ، اگر بخواهیم ببینیم که آیا فردی با نام Find می دهید. سپس این آرایه را به عنوان پارامتر به متد

در جدول وجود دارد یا نه. می توانیم از قطعه کد زیر استفاده کنیم: Watts و نام خانوادگی Simon

int intPosition;

Object[] arrValues = new Object[1];

objDataView.Sort = "au_fname, au_lname";

// Find the author named “Simon Watts”.

arrValues[0]= "Simon";

arrValues[1] = "Watts";

intPosition = objDataView.Find(arrValues);

فرستاده شو د . دلیل این امر هم در این Find به متد object نکته: دقت کن ید که در این قسمت حتماٌ باید آرای ه ای از نوع

مشتق م ی شوند. بنابراین اگر بخواهیم آرای ه ای داشته باشیم که هر object تمام نو ع های داده ای از کلاس NET. است که در

تعریف کنیم. در اینجا نیز لازم است آرای های داشته باشیم که object متغیری را بتوانیم در آن قرار دهیم، باید آن را از نوع

را به authors بتوانیم متغیری از هر نوع داد ه ای را در آن قرار دهی م . برای مثال، فرض کنید بخواهید جستجو در جدول

است را پیدا کن د . در این صورت، باید یک Ann گونه ای تغییر دهید که افرادی که سن آنها بالاتر از 25 و نیز نام آنها برا بر

متغیر از نوع عددی و یک متغیر از نوع رشت های را در آرایه قرار دهید.

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

417

در عمل ADO.NET -3-23 استفاده از کلا سهای

آشنا شدیم و مشاهده کردیم که چگونه م ی توان داده ها را به وسی ل ه این ADO.NET تاکنون با اصول کار کلا س های موجود در

بدست آورده و یا در آنها وارد کرد. اما تا این قسمت از فصل فقط ذهن خود را با SQL SERVER کلاس ها از بانک اطلاعاتی

یک سری مطالب تئوری درگیر کرده بودیم، و برای اینکه مطمئن شویم نحوه استفاده از این کلا س ها، متدها، خاصی ت ها و ...

را درست درک کرد ه ایم ، بهت ر ین را ه این است که از آنها در یک مثال عملی استفاده کنی م . در دو مثال بعدی با استفاده از

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

اس تفاده کرده و DataSet و نیز SqlCommand ،SqlConnection ،SqlDataAdapter در مثال اولی از کلا سهای

نمایش DataGrid بوسیله آنها یک برنامه ساده ایجاد م ی کنیم که داد ه ها را از یک بانک اطلاعاتی بدست آورد و در یک

دهد. در واقع برنام ه ای که در این قسمت خواهیم نوشت، عملکردی بسیار مشابه برنامه فصل قبل خواهد داش ت . البته با این

تفاوت عمده که در این قسمت به جای استفاده از ویزارد، از کد نویسی استفاده خواهیم کرد.

نکته: هنگام نوشتن برنام ه های واقعی، معمولاً از ویزارد و کدنویسی به صورت همزمان استفاده م ی کنند تا بتوانند به سرعت و

به راحتی برنام ه هایی با انعطا ف پذیری بالا ایجاد کنن د . کنترل هایی که در قسمت قبل با استفاده از جعبه ابزار به فرم اضافه

کردیم را در این قسمت با استفاده از کد ایجاد خواهیم کر د . البته نحوه استفاده آنها در هر دو روش یکسان خواهد بو د .

همچنین در فصل قبل اغلب از ویزاردها استفاده م ی کردیم، در صورتی که در این فصل بیشتر بر کدنویسی تمرکز خواهیم

کرد.

در برنامه DataSet -1 کاربرد -3-23

قبل از اینکه نوشتن برنام ه ی این قسمت ر ا شروع کنیم ، بهتر است که به ب ر رسی داده هایی که م ی خواهیم در این برنامه

2000 استخراج SQL Server در pubs نمایش دهیم و نیز رابطه ی بین آنها بپردازیم. اطلاعات این برنامه از بانک اطلاعاتی

2000 استفاده می کنید نیز باید همین اطلاعات را SQL Server به جای msde 7 و یا ، می شود. البته اگر از نسخه های 2005

مشاهده کنید. pubs در بانک اطلاعاتی

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

3 این جدو ل ها ر ا به همراه فیلدهای موجود در هر کدام و نیز - چاپ کرده اند و قیمت هر کدام را نمایش دهی م . در شکل 23

رابطه های بین آنها را نمایش م یدهد.

بدس  ت authors همانطور که در شکل مشاهده م ی کنید در این برنامه م ی خواهیم نام و نام خانوادگی نویسنده را از جدول

قرار دار د ، در برنامه نمایش دهی م . به علت اینکه یک کتاب titles آورده و به همراه عنوان و قیمت کتاب او که در جدول

می تواند بیش از یک نویسنده داشته باشد و نیز یک نویسنده نیز م ی تواند بیش از یک کتاب نوشته باشد ، اطلاعات این دو

به یکدیگر متصل شد هاند. titleauthor جدول در جدول دیگری به نام

3- شکل 23

mohsen_mahyar@yahoo.com - C# برنامه نویسی

418

ای که باید در این مورد SELECT با توجه به رابط ه ی بین جدول و نیز اطلاعاتی که م ی خواهیم از آنها استخراج کنی م ، دستور

استفاده کنیم مشابه زیر خواهد بود:

SELECT au_lname, au_fname, title, price

FROM authors

JOIN titleauthor ON authors.au_id = titleauthor.au_id

JOIN titles ON titleauthor.title_id = titles.title_id

ORDER BY au_lname, au_fname

خط اول این دستور نام فیل د هایی را که م ی خواهیم از جدول استخراج کنیم را نمایش م ی دهد و خط دوم هم مشخص کنند ه ی

titles و نیز authors نام جدول اصلی است که داد ه ها از آن استخراج م ی شوند. در این قسمت داد ه ها از دو جدول

را به عنوان جدول اصلی در نظر م یگیریم. authors استخراج می شوند، اما جدول

رابطه برقرار م ی کند. به این titleauthor و نیز همین ستون در جدول authors در جدول au_id خط سوم بین ستون

که مقدار titleauthor انتخاب شود ، تمام رکورد های موجود در جدول authors ترتیب هر زمان که یک رک و رد از جدول

باشد نیز انتخاب خواهند شد. authors آنها برابر با مقدار این ستون در رکورد انتخاب شده از جدول au_id ستون

رابطه برقرار title_id از طریق ستون titleauthor و جدو ل titles خط چهارم نیز مانند خط سوم، بین جدول

انتخاب شود، رکوردهای متناظر آن در جدو ل titleauthor می کند. به این ترتیب هر زمان که یک رکورد از جدو ل

نیز انتخاب خواهند ش د . خط آخر نیز اطلاعات را براساس نام خانوادگی و سپس نام ، به صورت صعودی مرتب titles

می کند.

برای درک آن کافی نباشد، اما در هر صورت برای اتمام این مثال کافی SELECT نکته: ممکن است که توضیحات این دستور

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

پیچیده ای برای انتخاب داد ه ها از چندین جدول SELECT اطلاعاتی رابطه ای را درک کرده باشید و نیز بتوانید د س تورات

بنویسید. بنابراین در این صورت بهتر است که کتاب هایی را در این زمینه نیز مطالعه کنید.

1- مثال 23

ایجاد کنید. DATASETEXAMPLE یک برنامه ی ویندوزی جدید به نام VS 1)با استفاده از

خاصی تهای فرم را به صورت زیر تغییر دهید: ،Properties 2)با استفاده از پنجره ی

600 قرار دهید. / را برابر با 230 Size خاصیت

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

419

قرار دهید. CenterScreen را برابر با StartPosition خاصیت

قرار دهید. Bound DataSet را برابر با Text خاصیت

به فرم برنامه اضافه کرده و خاصی ت های آن را به DataGridView در جعبه ابزار،یک کنترل Data 3)با استفاده از قسمت

صورت زیر تغییر دهید:

قرار دهید. grdAuthorTitles را برابر با Name خاصیت

قرار دهید. Top/Left/Right/Bottom را برابر با Anchor خاصیت

0 قرار دهید. / را برابر با 0 Location خاصیت

592 قرار دهید. / را برابر با 203 Size خاصیت

1 را باز کرده و ابتدا فضای نا مهایی که در طول برنامه به آنها نیاز خواهیم داشت را به Form 4)ویرایشگر کد مربوط به کلاس

1 اضافه کنید: Form برنامه اضافه کنید. برای این کار دستور زیر را به بالای تعریف کلاس

// Using Data and SqlClient namespaces...

using System.Data;

using System.Data.SqlClient;

public partial class Form1 : Form

{

}

5)در مرحله ی بعد لازم است که اشیای لازم برای دسترسی به بانک اطلاعاتی و دریافت داد ه ها را ایجاد کنی م . بنابراین کدهای

مشخص شده در زیر را به برنام ه ی خود اضافه کنی د . مطمئن شوید که اطلاعات مربوط به نام کاربری و نیز کلم ه ی عبور در

به درستی وارد شده است. ConnectionString

public partial class Form1 : Form

{

SqlConnection objConnection = new SqlConnection(

"server=localhost;database=pubs;" +

"user id=sa;password=");

SqlDataAdapter objDataAdapter = new SqlDataAdapter();

DataSet objDataSet = new DataSet();

public Form1()

{

نکته: دقت کنید که اگر سرور بانک اطلاعاتی که از استفاده م ی کنید در کامپیوتر دیگری به غیر از کامپیوتری که در حال

تغییر دهید . همچنین SQL Server را به نام کامپیوتر حاوی Server استفاده از آن هستید قرار دارد، باید مقدار پارامتر

را نیز به گونه ای تنظیم کنید که به یک نام کاربری و کلم هی عبور مناسب در سرور Password,User ID باید مقدار پارامتر

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

ذکر کنید اما در مقابل آن ConnectionString را Password که در سرور تعریف کرد ه اید کلمه عبور ندارد ، باید قسمت

.;=Password چیزی ننویسید. برای مثال

فرم به load برگردید و روی نوار عنوان آن دو بار کلیک کنید تا متد مربوط به روی  داد Forml 6)به قسمت طراحی فرم

صورت اتوماتیک ایجاد شود. سپس کد مشخص شده در زیر را به این متد اضافه کنید:

private void Form1_Load(object sender, EventArgs e)

{

// Set the SelectCommand properties...

objDataAdapter.SelectCommand = new SqlCommand();

objDataAdapter.SelectCommand.Connection =

objConnection;

objDataAdapter.SelectCommand.CommandText =

"SELECT au_lname, au_fname, title, price " +

"FROM authors " +

"JOIN titleauthor ON authors.au_id = " +

"titleauthor.au_id " +

"JOIN titles ON titleauthor.title_id = " +

mohsen_mahyar@yahoo.com - C# برنامه نویسی

420

"titles.title_id " +

"ORDER BY au_lname, au_fname";

objDataAdapter.SelectCommand.CommandType =

CommandType.Text;

// Open the database connection...

objConnection.Open();

// Fill the DataSet object with data...

objDataAdapter.Fill(objDataSet, "authors");

// Close the database connection...

objConnection.Close();

// Set the DataGridView properties

// to bind it to our data...

grdAuthorTitles.AutoGenerateColumns = true;

grdAuthorTitles.DataSource = objDataSet;

grdAuthorTitles.DataMember = "authors";

// Clean up

objDataAdapter = null;

objConnection = null;

}

4 مشاهده خواهید کرد. - 7)با اجرای برنامه، نتیجه ای مشابه شکل 23

4- شکل 23

دارای خاصیت درونی مرتب کردن داد هها است. بنابراین اگر روی یکی از نا م های DataGridView 8)دقت کنید که کنترل

ستون ها کلیک کنید، داد ه های موجود در ف رم براساس آن ستون مرتب م ی شوند. همچنین کلیک دوباره بر روی نام یک

ستون باعث می شود که داد هها برحسب آن ستون به صورت نزولی مرتب شوند.

نکته: در این برنامه به علت کمبود ج ا ، کدهای مربوط به مدیریت خطاها و استثناهای احتمالی حذف شده است ، اما بهتر است

در برنامه ای که می نویسید این کدها را نیز اضافه کنید.

2- مثال 23

انجام دهید تا داد هها بهتر نمایش داده شوند، آورده شده است: DataGridView -1 در زیر از تغییراتی که می توانید در یک

- عنوان ستون ها را برابر با نام مناسبی قرار دهید.

- اندازه ی هر ستون را به گون های تغییر دهید تا بتوان به راحتی داد ههای آن را مطالعه کرد.

- رنگ هر ردیف از اطلاعات را به گون های تغییر دهید که به صورت متمایز نمایش داده شوند.

- داده ها را در ستو نها به صورت راست - چین قرار دهید ( برای نمایش داده های عددی).

تغییرات مشخص شده در زیر را اعمال کنید: form_Load -2 برای انجام این موارد، در متد

private void Form1_Load(object sender, EventArgs e)

{// Set the SelectCommand properties...

objDataAdapter.SelectCommand = new SqlCommand();

objDataAdapter.SelectCommand.Connection =

objConnection;

objDataAdapter.SelectCommand.CommandText =

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

421

"SELECT au_lname, au_fname, title, price " +

"FROM authors " +

"JOIN titleauthor ON authors.au_id = " +

"titleauthor.au_id " +

"JOIN titles ON titleauthor.title_id = " +

"titles.title_id " +

"ORDER BY au_lname, au_fname";

objDataAdapter.SelectCommand.CommandType =

CommandType.Text;

// Open the database connection...

objConnection.Open();

// Fill the DataSet object with data...

objDataAdapter.Fill(objDataSet, "authors");

// Close the database connection...

objConnection.Close();

// Set the DataGridView properties

// to bind it to our data...

grdAuthorTitles.AutoGenerateColumns = true;

grdAuthorTitles.DataSource = objDataSet;

grdAuthorTitles.DataMember = "authors";

// Declare and set

// the currency header alignment property...

DataGridViewCellStyle objAlignRightCellStyle = new

DataGridViewCellStyle();

objAlignRightCellStyle.Alignment =

DataGridViewContentAlignment.MiddleRight;

// Declare and set the alternating rows style...

DataGridViewCellStyle objAlternatingCellStyle = new

DataGridViewCellStyle();

objAlternatingCellStyle.BackColor = Color.WhiteSmoke;

grdAuthorTitles.AlternatingRowsDefaultCellStyle =

objAlternatingCellStyle;

// Declare and set the style for currency cells ...

DataGridViewCellStyle objCurrencyCellStyle = new

DataGridViewCellStyle();

objCurrencyCellStyle.Format = "c";

objCurrencyCellStyle.Alignment =

DataGridViewContentAlignment.MiddleRight;

// Change column names

// and styles using the column name

grdAuthorTitles.Columns["price"].HeaderCell.Value =

"Retail Price";

grdAuthorTitles.Columns["price"].HeaderCell.Style =

objAlignRightCellStyle;

grdAuthorTitles.Columns["price"].DefaultCellStyle =

objCurrencyCellStyle;

// Change column names

// and styles using the column index

grdAuthorTitles.Columns[0].HeaderText = "Last Name";

grdAuthorTitles.Columns[1].HeaderText = "First Name";

grdAuthorTitles.Columns[2].HeaderText = "Book Title";

grdAuthorTitles.Columns[2].Width = 225;

// Clean up

objDataAdapter = null;

objConnection = null;

objCurrencyCellStyle = null;

objAlternatingCellStyle = null;

objAlignRightCellStyle = null;

}

را قال ب بندی DataGrid می توانید تنظیمات نمایشی سطر و ستو ن های DataGridViewCellStyle به کمک کلاس

کنید.

5 نمایش داده م ی شوند . با - -3 مجددا برنامه را اجرا کنی د . مشاهده خواهید کرد که داد ه ها در جدولی مشابه شکل 23

4 متوجه تفاوت های ایجاد شده در برنامه خواهید شد - مقایسه ی این شکل با شکل 23

5- شکل 23

mohsen_mahyar@yahoo.com - C# برنامه نویسی

422

-4-23 اتصال داده ها

بهترین کنترل برای نمایش تمام داد ه ها در فرم برنامه اس ت . این کنترل علاوه براین قابلیت م ی تواند DataGridView کنترل

به راحتی به کاربر اجازه دهد که داد ه ها را حذف و یا ویرایش کند و یا داد ه های جدید را در جدول وارد کند. اما با این وجود

ممکن است در شرای ط ی بخواهید در هر لحظه فقط یک سطر از داد ه ها را در برنامه نمایش دهی د . در این مواقع تنها راه این

بر روی فرم قرار داده و هر یک از آنه ا را به یکی از فیلدهای جدول در برنامه TextBox است که تعدادی کنترل ساده مانند

متصل کنیم، سپس در هر لحظه اطلاعات مربوط به یک سطر از اطلاعات را در این کنتر ل ها قرار دهیم با استفاده از این روش

می توانید کنترل بیشتری روی داد ه ها داشته باشی د . اما کدی که برای این کار باید در برنامه وارد کنید نیز مشک ل ت ر خواهد

بود، زیرا باید برنام ه ای بنویسید که هر یک از کنتر ل های روی فرم را به فیلد مربوط متصل کن د . سپس قسمتی را در فرم

برنامه طراحی کنید که به وسیله آن بتوان در بین سطرهای اطلاعات حرکت کر د . بنابراین برای انجام این کار لازم است که

درگیر اموری مانند اتصال کنترل های ساده به داده ها و نیز مدیریت اتصال شویم.

در بحث راجع به اتصال داد ه ها، منظور از کنتر ل های ساده کنتر ل هایی هستند که در هر لحظه فقط م ی توانند مقدار یک داده

و یا کنتر ل هایی از این قبیل . RadioButton ،CheckBox ،TextBox را در خود نگهداری کنند، برای مثال مانن د

که در هر لحظه می توانند بیش از یک آیتم از داد ه های DataGridView و یا ListBox ،ComboBox کنترل هایی مانند

موجود در برنامه را نمایش دهند به عنوان کنتر لهای ساده در نظر گرفته نم یشوند.

:CurrencyManager,BindingContext-1-4-23

است که اتصالات کنتر ل های درون فرم را مدیریت م ی کند. بنابراین به علت BindingContext هر فرم دارای شیئی از نوع

اینکه فرم برنامه شما به صورت درونی دارای چنین شیئی است، نیازی نیست که آن را در یک کد ایجاد کنید.

را مدیریت م ی کند . وظیفه ی CurrencyManager در حقیقت یک مجموعه از اشی ا ء از نوع BindingContext شی

متصل هستند و منبع داد ه ای، ( DataSet نیز این است که بین کنتر ل هایی که به منبع داد ه ای ( مثلا CurrencyManager

و نیز این کنتر ل ها با دیگر کنتر ل هایی که در فرم به همان منبع داد ه ای متصل هستند هماهنگی برقرار کن د . به این ترتیب

می توان مطمئن شد که ت مام این کنتر ل ها در فرم در حال نمایش داد ه های موجود در یک سطر هستن د . شی

،DataTable ،DataSet می تواند این هماهنگی را بین کنتر ل ها و منابع داد ه ای مختلفی مانن د CurrencyManager

ایجاد کن د . هر زمان که منبع داد ه های جدید به فرم برنامه اضاف ه کنید، یک ش ی DataSetView ،DataView

جدید نیز به صورت اتوماتیک ایجاد م ی شود. به این ترتیب کار با کنتر لهای متصل به یک منبع CurrencyManager

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

CurrencyManager اگر در برنام ه ی خود از چندین منبع داد ه ای مختلف استفاده م ی کنید، م ی توانید ی ک متغیر از نوع

ارجاع دهی د . به BindingContext مربوط به منبع داد ه ای مورد نظر خود در CurrencyManager ایجاد کرده و آن را ب ه

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

423

دسترسی داشته BindingContext مورد نظر خود CurrencyManager این ترتیب به وسیل ه ی این متغیر م ی توانید به

باشید و به وسیل هی آن نمایش داد هها را بر روی فرم کنترل کنید.

ای که در برنام هی قبل ایجاد کرده بودیم، یک ارجاع به شی DataSet قطعه کد زیر با استفاده از شی

را کنترل م ی کرد ایجاد م ی کند. برای این کا ر ، ابتدا یک Authors ای که منبع داد ه ای مربوط به جدول CurrencyManager

مربوط به منبع CurrencyManager ایجاد می کنیم. سپس مقدار این متغیر را برابر با CurrencyManager متغیر از کلا س

ذ خیره BindingContext قرار م ی دهیم. البته دقت کنید شیئی که د ر BindingContext در objDataSet داده ای

CurrencyManager نیست و باید با استفاده از عملکرد ( ) آن را به صورت صریح به CurrencyManager می شود از

تبدیل کنیم:

CurrencyManager objCurrencyManager;

objCurrencyManager =

(CurrencyManager)(this.BindingContext[objDataSet]);

موق عیت Position بعد از اینکه با استفاده از این کد ارجاعی به این شی ایجاد کردی م ، می تولنیم با استفاده از خاصیت

رکورد جاری را کنترل کنیم. برای مثال، کد زیر موقعیت رکورد جاری را یک واحد افزایش می دهد:

یک منبع داد ه ای، رکوردی است که تمام کنتر ل های ساده ی فرم که به این CurrencyManager منظور از رکورد جاری د ر

منبع داد های متصل شده اند باید اطلاعات آن رکورد را نمایش دهند.

objCurrencyManager.Position += 1;

متصل شد ه اند، اطلاعات رکورد قبلی را objDataSet و یا دستور زیر باعث م ی شود که تمام کنتر ل های ساده ای که به

نمایش دهند:

objCurrencyManager.Position -= 1;

می توانیم از کد زیر استفاده کنیم: objDataSet همچنین برای نمایش اطلاعات مربوط به اولین رکورد در

objCurrencyManager.Position = 0;

حاوی تعداد رکوردهایی است که در منبع داد ه ای که به وسیل ه ی CurrencyManager در کلاس Count خاصیت

مدیریت م ی شود وجود دار د . بنابراین برای نمایش اطلاعات مربوط به رکورد آخر در فرم برنامه CurrencyManager

می توانید از کد زیر استفاده کنید:

objCurrencyManager.Position = objCurrencyManager.Count - 1;

دقت کنید که در این کد از تعداد رکور د های موجود منهای یک برای رفتن به آخرین رکورد استفاده کرد ه ایم. دلیل این کار

این است که اندیس رکور د ها در این ش ی از صفر شروع م ی شود. بنابر این اندیس رکورد آخر برابر با تعداد کل رکوردها منه ا ی

یک خواهد بود.

-2-4-23 اتصال کنترل ها

آن کنترل استفاده کنی م . این خاصیت از کلاس DataBindings برای اتصال یک کنترل به یک منبع داد ه ای ،باید از خاصیت

Add است و خود نیز دارای چندین خاصیت و متد مختلف است . اما در این قسمت از متد DataBindingsCollection

آن استفاده خواهیم کرد. این متد سه پارامتر دریافت کرده و به صورت زیر فراخوانی م یشود:

object.DataBindings.Add(propertyName,

dataSource, dataMember);

این پارامترها برای موارد زیر مورد استفاده قرار می گیرند:

نام کنترلی است که می خواهیم یک اتصال جدید برای آن ایجاد کنیم. :Object

حاوی نام خاصیتی است که م یخواهیم در طول برنامه مقدار خود را از منبع داد های دریافت کند. :propertyName

mohsen_mahyar@yahoo.com - C# برنامه نویسی

424

نام منبع داد ه ای است که م ی خواهیم اطلاعات مورد نیاز برای این کنترل ر ا از آن دریافت ک نیم و م ی توان :dataSource

یا هر منبع داد های دیگری باشد. DataTable ،DataView ،DataSet شامل یک

از propertyName مشخص کننده ی نام فیلدی از منبع داد ه ای است که م ی خواهیم آن را ب ه خاصیت :dataMember

کنترل متصل کنیم.

را به txtFirstName درکنترل Text در قطعه کد زیر آورده شده است.کد زیر خاصی ت Add مثالی ازنحوه استفاده از متد

متصل می کند: objDataView از شی au-fname فیلد

txtFirstName.DataBindings.Add("Text",

objDataView, "au_fname");

در مواقعی ممکن است بعد از ایجاد اتصال د ر یک کنترل بخواهید تمام اتصالات آن با منابع داد های را حذف کنید. برای این

استفاده کنید. این متد تمام اتصالاتی که برای ControlBindingsCollection درکلاس Clear کار می توانید از متد

خاصیت های مختلف یک کنترل تعریف شده بود را حذف می کند. نحوه ی استفاده از این متد در کد زیر نشان داده شده است:

txtFirstName.DataBindings.Clear();

آشنا شدیم . بهتر CurrencgManager و نیز ControlBindingsCollection ،BindingContext حال که با اشیا ی

است نحو هی استفاده از آنها در یک برنامه را نیز مشاهده کنیم.

3-اتصال کنترل های ساده به منبع داد های - مثال 23

ایجاد کنید. BindingExample یک پروژه با نام VS -1 با استفاده از

به فرم اضافه کنی د . این کنترل همانند کنترل های دیگر به قسمت پایین بخش طراحی فرم مربوط ToolTip -2 یک کنترل

1 اضافه خواهد شد. Form به

خاصیت های آن را به صورت زیر Properties -3 بر روی فرم برنامه کلیک کنید تا انتخاب شو د . سپس با استفاده از پنجره

تغییر دهید :

قرار دهید. FixedDialog را برابر FormBorderStyle خاصیت

قرار دهید. False را برابر با maximizeBox خاصیت

قرار دهید. False را برابر با MinimizeBox خاصیت

360 قرار دهید. " را برابر با 430 Size خاصیت

قرار دهید. CenterScreen را برابر با StartPosition خاصیت

قرار دهید. Binding Controls را برابر با Text خاصیت

4) در این قسمت باید کنتر ل هایی را به فرم برنامه اضافه کرده و سپس خاصی ت های مختلف آنها را تنظیم کن ی د تا فرم برنامه

6 شود. - مشابه شکل 23

این مراحل به این دلیل طی م ی شوند تا ظاهر برنامه همانند یک برنام ه ی واقع ی شود . با این وجود ، این مراحل اهمیت زیادی

6 ایجاد کنی د . البته در این صورت - ندارد و در صورت لزوم م ی توانید از آنها صرفنظر کرده و خودتان فرمی را مشابه شکل 23

دقت کنید که اسامی کنتر ل ها باید مشابه آنچه باشد که در این قسمت عنوان شده اس ت . در غیر اینصورت ممکن اس ت در

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

6- شکل 23

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

425

به فرم برنامه اضافه کرده و خاصی تهای آن را به صورت زیر دهید: GroupBox 5) یک کنترل

را برابر با 128;408 قرار دهید. Size خاصیت o

را برابر با 8;8 قرار دهید. Location خاصیت o

قرار دهید. Authors && Titles را برابر با Text خاصیت o

باید از علامت && استفاده کنی د . استفاده از یک & در GroupBox نکته: برای نمایش علا مت & در عنوان یک کنترل

عنوان باعث می شود که کا راکتر بعد از آن با زیر خط نمایش داده شود.

اضافه کنید: GroupBoxl با خاصی تهایی که در جدول زیر عنوان شده است را به کنترل Label 6 ) چهار کنترل

Name Location Size Text AutoSize

Label1 26;8 16;64 Last Name False

Label2 50;8 16;64 First Name False

Label3 74;8 16;56 Book Title False

Label4 98;8 16;64 Price False

در برنامه اضافه کرده و خاصی ت های آن را بر اساس GroupBoxl نیز ب ه TextBox 7) با استفاده از جعبه ابزار چهار کنتر ل

جدول زیر تنظیم کنید:

Name Location Size ReadOnly

txtLastName 24;72 20;88 True

txtFirstName 48;72 20;88 True

txtBookTitle 72;72 20;328 False

txtPrice 96;72 20;48 False

اسلام احمد زاده - 09177112161 - C# برنامهنویسی

426

دیگری به فرم اضافه کرده و خاصی ت های آن آن را طبق لیست زیر تنظیم GroupBox 8) با استفاد ه از جعبه ابزار کنتر ل

کنید:

را برابر با 144;8 قرار دهید. Location خاصیت

را برابر با 168;408 قرار دهید. Size خاصیت

قرار دهید. Navigation را برابر با Text خاصیت

2 اضافه کرده و بر اساس جدول زیر آنها را تنظیم کنید: GroupBox به Label 9) دو کنترل

Name Location Size Text AutoSize

Label5 23;8 16;64 Field False

Label6 48;8 16;80 SearchCriteria False

،CboField آن را برابر با Name 2 اضافه کنید. خاصیت GroupBox به ComboBox 10 ) با استفاده از جعبه ابزار یک کنترل

را برابر با DropDownStyle را برابر 21;88 و خاصیت Size را برابر با 21;88 ، خاصیت Location خاصیت

قرار دهید. DropDownList

2 اضافه کرده و خاصی تهای آن را براساس جدول زیر تغییردهید: GroupBox به TextBox 11 ) دو کنترل

Name Location Size TabStop TextAlign

txtSearchCriteria 48;88 20;200 - -

txtRecordPosition 130;152 20;85 False Center

2 اضافه کرده و خاصیت های آنها را به صورت زیر تغییردهید: GroupBox به Button 12 )ده کنترل

ToolTip On

ToolTip1

Name Location Size Text

btnPerformSort 16;304 24;96 Perform Sort -

Perform -

Search btnPerformSearch 48;304 24;96

btnNew 88;40 24;72 New -

btnAdd 88;120 24;72 Add -

btnUpdate 88;200 24;72 Update -

btnDelete 88;280 24;72 Delete -

btnMoveFirst 128;88 24;29 >| Move First

Move

Previous

btnMovePrevious 128;120 24;29 >

btnMoveNext 128;200 24;29 < Move Next

btnMoveLast 128;272 24;29 |< Move Last

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

427

Size و یا Location ،Name به برنامه اضافه کنی د . نیازی به تغییر خاصی تهای StatusStrip 13 )در آخر نیز یک کنترل

را به آن اضافه کنید. StatusLabel این کنترل نیست. بعد از انتخاب این کنترل، با استفاده از منوی کنار آن یک کنترل

6 باشد. - 14 )بعد از اتمام این مراحل، فرم کامل شد هی برنامه باید مشابه شکل 23

رفته و با قرار دادن کد Forml 15 )حال قسمت کدنویسی برنامه را شروع م ی کنیم. به قسمت ویرایشگر کد مربوط به کلاس

را به برنامه اضافه کنید: System.Data.SqlClient و System.Data زیر در بالای کدها، فضای نام

// Import Data and SqlClient namespaces

using System.Data;

using System.Data.SqlClient;

16 )سپس اشیایی که باید به صورت سراسری در برنامه وجود داشته باشند را در ابتدای کلاس تعریف کنی م . همچنین یک

ای که م ی خواهیم در طول برنامه به کار ببریم را در آن قرار م ی دهیم. بنابراین کد زیر SQL رشته ی ثابت تعریف کرده و دستور

اضافه کنید: Forml را به ابتدای کلاس

public partial class Form1 : Form

{

// Constant strings

private const string _CommandText =

"SELECT authors.au_id, au_lname, au_fname, " +

"titles.title_id, title, price " +

"FROM authors " +

"JOIN titleauthor ON authors.au_id = " +

"titleauthor.au_id " +

"JOIN titles ON titleauthor.title_id = " +

"titles.title_id " +

"ORDER BY au_lname, au_fname";

private const string _ConnectionString =

"server=localhost;database=pubs;" +

"user id=sa;password=;";

// Declare global objects...

SqlConnection objConnection;

SqlDataAdapter objDataAdapter;

DataSet objDataSet;

DataView objDataView;

CurrencyManager objCurrencyManager;

را براساس تنظیمات سرور بانک اطلاعاتی خود تغییر ConnectionString ، نکته: قبل از وارد کردن قطعه کد بالا در برنامه

مربوط به حساب کاربری خود را وارد کرده و همچنین اگر سرور روی کامپیوتر دیگری قرار Password-User ID. دهید

نام کامپیوتر سرور در شبکه را وارد کنید. localhost دارد، به جای استفاده از

17 )کد درون متد سازنده ی فرم را به صورت زیر تغییر دهید:

public Form1()

{

objConnection = new SqlConnection(_ConnectionString);

objDataAdapter = new SqlDataAdapter(_CommandText, bjConnection);

InitializeComponent();

}

است . این زیربرنامه به همراه FillDataSetAndView 18 )اولین زیر برنامه ای که باید ایجاد کنیم ، زیربرنامه ای به نا م

بعد از تعربف متغیرها اضافه کنید: ،Forml چند زیربرنام هی دیگر در ابتدای برنامه فراخوانی می شوند.کد زیر را به

private void FillDataSetAndView()

{

// Initialize a new instance of the DataSet object...

objDataSet = new DataSet();

// Fill the DataSet object with data...

objDataAdapter.Fill(objDataSet, "authors");

// Set the DataView object to the DataSet object...

objDataView = new DataView(

objDataSet.Tables["authors"]);

// Set our CurrencyManager object

// to the DataView object...

objCurrencyManager = (CurrencyManager)( this.BindingContext[objDataView]);

}

mohsen_mahyar@yahoo.com - C# برنامه نویسی

428

19 )در این قسمت باید زیر برنام ه ای به فرم اضافه کنیم تا کنتر ل های موجود در فرم را به فیلدهای مربوط به آنها د ر

اضافه کند: DataView

private void BindFields()

{

// Clear any previous bindings...

txtLastName.DataBindings.Clear();

txtFirstName.DataBindings.Clear();

txtBookTitle.DataBindings.Clear();

txtPrice.DataBindings.Clear();

// Add new bindings to the DataView object...

txtLastName.DataBindings.Add("Text",

objDataView, "au_lname");

txtFirstName.DataBindings.Add("Text",

objDataView, "au_fname");

txtBookTitle.DataBindings.Add("Text",

objDataView, "title");

txtPrice.DataBindings.Add("Text",

objDataView, "price");

// Display a ready status...

ToolStripStatusLabel1.Text = "Ready";

}

20 )سپس زیربرنام های به کلاس اضافه می کنیم که موقعیت رکورد جاری را در فرم برنامه نمایش دهد:

private void ShowPosition()

{

// Always format the number

// in the txtPrice field to include cents

try

{

txtPrice.Text =

Decimal.Parse(txtPrice.Text).ToString("##0.00");

}

catch(System.Exception e)

{

txtPrice.Text = "0";

txtPrice.Text =

Decimal.Parse(txtPrice.Text).ToString("##0.00");

}

// Display the current position

// and the number of records

txtRecordPosition.Text =

(objCurrencyManager.Position + 1) +

" of " + objCurrencyManager.Count;

}

21 )تا اینجا زیربرنام ه های لازم را به برنامه اضافه کرد ه ایم، اما در هیچ قسمت از کد از این زیربرنام ه های ایجاد شده استفاده

نکرده ایم.این زیر برنام ه ها لازم است که قبل از نمایش داده شدن فرم و هنگام بارگذاری آن فراخوانی شون د . بنابراین به

فرم ایجاد شود (دقت Load قسمت طراحی فرم بروید و روی قسمت خالی از فرم دو بار کلیک کنید تا متد مربوط به رویدا د

سپس کد مشخص .(GroupBox کنید که باید در یک قسمت خالی از فرم دو بار کلیک کنید، نه در قسمتی خالی از کنترل

شده در زیر را به این متد اضافه کنید:

private void Form1_Load(object sender, EventArgs e)

{

// Add items to the combo box...

cboField.Items.Add("Last Name");

cboField.Items.Add("First Name");

cboField.Items.Add("Book Title");

cboField.Items.Add("Price");

// Make the first item selected...

cboField.SelectedIndex = 0;

// Fill the DataSet and bind the fields...

FillDataSetAndView();

BindFields();

// Show the current record position...

ShowPosition();

}

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

429

22 )حال باید کد کلیدهای مربوط به حر ک ت بین رکوردها را در برنامه وارد کنی م . برای این کار لازم است که چهار بار به قسمت

،btnMoveLast ،btnMovePrevious ،btnMoveNext طراحی فرم بروید و روی هر کدام از دکمه های

کلیک کنید تا متد مربوط به رویداد کلیک هر یک از آنها ایجاد شو د . کد مشخص شده در زیر ر ا به متد btnMoveFirst

اضافه کنید: btnMoveFirst کنترل Click مربوط به رویداد

private void btnMoveFirst_Click(object sender, EventArgs e)

{

// Set the record position to the first record...

objCurrencyManager.Position = 0;

// Show the current record position...

ShowPosition();

}

اضافه کنید: btnMovePrevious کنترل Click 23 )کد زیر را به متد مربوط به رویداد

private void btnMovePrevious_Click(object sender,

EventArgs e)

{

// Move to the previous record...

objCurrencyManager.Position -= 1;

// Show the current record position...

ShowPosition();

}

اضافه کنید: btnMoveNext_Click 24 )کد زیر را به متد

private void btnMoveNext_Click(object sender, EventArgs e)

{

// Move to the next record...

objCurrencyManager.Position += 1;

//Show the current record position...

ShowPosition();

}

قرار دهید: btnMoveLast_Click 25 )در آخر نیز برای تکمیل این قسمت لازم است که کد زیر را در متد

private void btnMoveLast_Click(object sender, EventArgs e)

{

// Set the record position to the last record...

objCurrencyManager.Position =

objCurrencyManager.Count - 1;

// Show the current record position...

ShowPosition();

}

26 )تا این قسمت کد زیادی را در برنامه وارد کرد ه ایم و احتمالاً مشتاق هستید که نتیج ه ی آن را مشاهده کنی د . برنامه را اجرا

متصل شده اند . روی کلیدهای DataView کنید. مشاهده خواهید کرد که کنتر ل های فرم هر یک به فیلد مربوط به خود در

برای ایجاد هماهنگی بین CurrencyManager مربوط به ابتدا و یا انتهای رکوردها کلیک کنید تا نحو ه ی عملکرد کلا س

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

7 مشاهده کنی د . تا اینجا در فر م برنامه فقط کلیدهای مربوط به جاب هجا شدن - با اجرای برنامه باید فرمی را مشابه شکل 23

بین رکوردها عمل م ی کنند. با کلیک کردن روی هر یک از کلیدهای بعدی و قبلی و یا روی کلیدهای مربوط به ابتدا و انتها

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

دهید، عدد نمایش داده شده در کادر در فرم برنامه نیز تغییر کرده و شماره رکورد جاری را نمایش م یدهد.

7- شکل 23

mohsen_mahyar@yahoo.com - C# برنامه نویسی

430

اگر در رکورد اول باشید، می توانید روی کلید مربوط به رکورد قبلی کلیک کنید ، اما هیچ اتفاقی رخ نخواه د داد، زیرا هم

اکنون در رکورد قبلی هستی د . همچنین می توانید به آخرین رکورد بروید و روی کلید مربوط به رکورد بعدی کلیک کنی د ، اما

باز هم هیچ تغییری را مشاهده نخواهیم کرد، زیرا در آخرین رکورد هستید.

همچنین اگر ماوس را روی هر یک از این دکم ه ها ببرید، توضیحی را مشاهده خواهیم کرد که عملکرد کلید را توضی ح

می دهد. این مورد فقط برای ایجاد رابط کاربری بهتر اضافه شده است.

نکته: قسمت ____________های مربوط به مدیریت خطاها و استثناهای احتمالی از کد این قسمت حذف شد ه اند تا جای کمتری گرفته شود .

در هنگام وارد کردن این کد بهتر است که این قسمت را نیز اضافه کنید.

4-اضافه کردن قابلیت مرت بسازی به برنامه - مثال 23

دو بار کلیک کنید تا متد مربوط به رویداد Perform Sort بروید و روی دکمه ی Forml 1)به قسمت طراحی فرم مربوط به

این کنترل ایجاد شود. سپس کد مشخص شده در زیر را به این متد اضافه کنید: Click

private void btnPerformSort_Click(object sender,

EventArgs e)

{

// Determine the appropriate item selected and set the

// Sort property of the DataView object...

switch(cboField.SelectedIndex)

{

case 0: // Last Name

objDataView.Sort = "au_lname";

break;

case 1: // First Name

objDataView.Sort = "au_fname";

break;

case 2: // Book Title

objDataView.Sort = "title";

break;

case 3: // Price

objDataView.Sort = "price";

break;

}

// Call the click event for the MoveFirst button...

btnMoveFirst_Click(null, null);

// Display a message

// that the records have been sorted...

ToolStripStatusLabel1.Text = "Records Sorted";

}

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

431

موجود در فرم یک ComboBox 2)برنامه را اجرا کنید تا قابلیتی را که در این قسمت به برنامه اضافه کردی م ، ببینید. در کنترل

- کلیک کنید تا داد هها براساس آن ستون مرتب شود. شکل 23 Perform Sort ستون را انتخاب کرده و سپس روی دکمه

مرتب شد هاند Price 8 فرم برنامه را در حالتی نمایش م یدهد که داده های موجود در آن براساس ستون

8- شکل 23

5- اضافه کردن قابلیت جستجو به برنامه - مثال 23

آن Click دو بار کلیک کنید تا متد مربوط به رویدا د Perform Search 1)به قسمت طراحی فرم بروید و روی دکمه ی

ایجاد شود. سپس کد مشخص شده در زیر را در این متد وارد کنید:

private void btnPerformSearch_Click(object sender,

EventArgs e)

{

// Declare local variables...

int intPosition;

// Determine the appropriate item selected and set the

// Sort property of the DataView object...

switch(cboField.SelectedIndex)

{

case 0: // Last Name

objDataView.Sort = "au_lname";

break;

case 1: // First Name

objDataView.Sort = "au_fname";

break;

case 2: // Book Title

objDataView.Sort = "title";

break;

case 3: // Price

objDataView.Sort = "price";

break;

}

// If the search field is not price then...

if (cboField.SelectedIndex < 3)

{

// Find the last name, first name, or title...

intPosition =objDataView.Find(txtSearchCriteria.Text);

}

else

{

// otherwise find the price...

intPosition = objDataView.Find(

اسلام احمد زاده - 09177112161 - C# برنامهنویسی

432

Decimal.Parse(txtSearchCriteria.Text));

}

if (intPosition == -1)

{

// Display a message

// that the record was not found...

ToolStripStatusLabel1.Text = "Record Not Found";

}

else

{

// Otherwise display a message that the record

// was found and reposition the CurrencyManager

// to that record...

ToolStripStatusLabel1.Text = "Record Found";

objCurrencyManager.Position = intPosition;

}

// Show the current record position...

ShowPosition();

}

2)برنامه را اجرا کنید تا ق ابلیت جدید آن را نیز امتحان کنی م . فیلدی که م ی خواهید جستجو براساس آن صورت گیرد را از

وارد کنید. در آخر نیز Search Criteria انتخاب کرده و سپس عبارت مورد جستجو را در داخل فیلد ComboBox داخل

کلیک کنید. Perform Search روی دکمه

اگر رکورد مورد نظر شما در بین دا د ه ها پیدا شود مشاهده خواهید کرد که اطلاعات آن رکورد در فرم نمایش داده م ی شود و

موقعیت رکورد جاری به رکورد پیدا شده تغییر م ی کند. همچنین پیغامی در نوار وضعیت نوشته م ی شود و مشخص م ی کند که

9). همچنین اگر هیچ رکوردی پیدا نشود، متنی در نوار وضعیت نوشته می شود و - رکورد مورد نظر پیدا شده است (شکل 23

مشخص می کند که داده ی مورد نظر پیدا نشده است.

9- شکل 23

6-اضافه کردن رکورد جدید - مثال 23

آن click دو بار کلیک کنید تا متد مربوط به رویداد btnNew بروید و روی دکم ه ی Forml 1) ابتدا به قسمت طراحی فرم

ایجاد شود. سپس کد مشخص شده در زیر را در این متد وارد کنید:

private void btnNew_Click(object sender, EventArgs e)

{

// Clear the book title and price fields...

txtBookTitle.Text = "";

txtPrice.Text = "";

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

433

}

را وارد کنی م . این متد م سئول اضافه کر د ن یک رکورد داد ه ای جدید به btnAdd_Click 2) حال باید کد مربوط به متد

برنامه است . این زیربرنامه، طولان ی ترین زیربرنامه ای است که در این پروژه وجود دارد و کد زیادی را شامل م ی شود دلیل

آن تیز رابط ه ی بین عنوان کتا ب ها و نیز نویسندگان آنها و نیز کلید اصلی که برای عنوان کتا ب ها استفاده م ی شود است .

این کنترل ایجاد شو د . Click دو بار ک لیک کنید تا متد مربوط به رویداد Add به ق سمت طراحی فرم بروید و روی دکم ه

سپس کد زیر را در این متد وارد کنید:

private void btnAdd_Click(object sender, EventArgs e)

{

// Declare local variables and objects...

int intPosition, intMaxID;

String strID;

SqlCommand objCommand = new SqlCommand();

// Save the current record position...

intPosition = objCurrencyManager.Position;

// Create a new SqlCommand object...

SqlCommand maxIdCommand = new SqlCommand(

"SELECT MAX(title_id)" +

"FROM titles WHERE title_id LIKE 'DM%'",

objConnection);

// Open the connection, execute the command

objConnection.Open();

Object maxId = maxIdCommand.ExecuteScalar();

// If the MaxID column is null...

if (maxId == DBNull.Value)

{

// Set a default value of 1000...

intMaxID = 1000;

}

else

{

// otherwise set the strID variable

// to the value in MaxID...

strID = (String)maxId;

// Get the integer part of the string...

intMaxID = int.Parse(strID.Remove(0, 2));

// Increment the value...

intMaxID += 1;

}

// Finally, set the new ID...

strID = "DM" + intMaxID.ToString();

// Set the SqlCommand object properties...

objCommand.Connection = objConnection;

objCommand.CommandText = "INSERT INTO titles " +

"(title_id, title, type, price, pubdate) " +

"VALUES(@title_id,@title,@type,@price,@pubdate);" +

"INSERT INTO titleauthor (au_id, title_id) " +

"VALUES(@au_id,@title_id)";

// Add parameters for the placeholders in the SQL in

// the CommandText property...

// Parameter for the title_id column...

objCommand.Parameters.AddWithValue("@title_id",

strID);

// Parameter for the title column...

objCommand.Parameters.AddWithValue("@title",

txtBookTitle.Text);

// Parameter for the type column

objCommand.Parameters.AddWithValue("@type", "Demo");

// Parameter for the price column...

objCommand.Parameters.AddWithValue("@price",

txtPrice.Text).DbType = DbType.Currency;

// Parameter for the pubdate column

objCommand.Parameters.AddWithValue("@pubdate",

DateTime.Now);

// Parameter for the au_id column...

objCommand.Parameters.AddWithValue("@au_id",

this.BindingContext[objDataView,"au_id"].Current);

// Execute the SqlCommand object

// to insert the new data...

mohsen_mahyar@yahoo.com - C# برنامه نویسی

434

try

{

objCommand.ExecuteNonQuery();

}

catch(SqlException SqlExceptionErr)

{

MessageBox.Show(SqlExceptionErr.Message);

}

// Close the connection...

objConnection.Close();

// Fill the dataset and bind the fields...

FillDataSetAndView();

BindFields();

// Set the record position

// to the one that you saved...

objCurrencyManager.Position = intPosition;

// Show the current record position...

ShowPosition();

// Display a message that the record was added...

ToolStripStatusLabel1.Text = "Record Added";

}

ای را اجرا م یکند که فقط یک مقدار اسکالر برم یگردانند. SQL دستورات ExecuteScalar متد

3) برنامه را اجرا کرده و کاربری را که م ی خواهید عنوان کتاب جدیدی را ب ر ای او ثبت کنید، انتخاب کنید، سپس روی

خالی خواهند شد و م ی توان داده های مربوط به Price ،BookTitle کلیک کنی د . به این ترتیب کادرهای Add دکمه ی

10 وارد کنید. در برنامه به تعداد رکوردهایی که هم اکنون وجود دارند توجه کنید. - کتاب جدید را همانند شکل 23

10- شکل 23

کلیک کنید . به این ترتیب پیغامی در نوار Add 4) حال نام کتاب و قسمت آن ر ا فیلدهای مربوطه وارد کرده و روی دکمه ی

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

مشخص است تعداد رکوردها در برنامه یک واحد افزایش پیدا می کند.

11- شکل 23

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

435

7- ویرایش داده ها - مثال 23

آن ایجاد شو د . click دو بار کلیک کنید تا متد مربوط به رویداد btnUpdate 1) به قسمت طراحی فرم و روی دکم ه ی

سپس کد مشخص شده در زیر را در این متد وارد کنید:

private void btnUpdate_Click(object sender, EventArgs e)

{

// Declare local variables and objects...

int intPosition;

SqlCommand objCommand = new SqlCommand();

// Save the current record position...

intPosition = objCurrencyManager.Position;

// Set the SqlCommand object properties...

objCommand.Connection = objConnection;

objCommand.CommandText = "UPDATE titles " +

"SET title = @title, price = @price " +

"WHERE title_id = @title_id";

objCommand.CommandType = CommandType.Text;

// Add parameters for the placeholders in the SQL in

// the CommandText property...

// Parameter for the title field...

objCommand.Parameters.AddWithValue("@title",

txtBookTitle.Text);

// Parameter for the price field...

objCommand.Parameters.AddWithValue("@price",

txtPrice.Text).DbType = DbType.Currency;

// Parameter for the title_id field...

objCommand.Parameters.AddWithValue("@title_id",

this.BindingContext[objDataView,"title_id"].Current);

// Open the connection...

objConnection.Open();

// Execute the SqlCommand object to update the data...

objCommand.ExecuteNonQuery();

// Close the connection...

objConnection.Close();

// Fill the DataSet and bind the fields...

FillDataSetAndView();

BindFields();

// Set the record position

// to the one that you saved...

objCurrencyManager.Position = intPosition;

// Show the current record position...

ShowPosition();

// Display a message that the record was updated...

ToolStripStatusLabel1.Text = "Record Updated";

}

mohsen_mahyar@yahoo.com - C# برنامه نویسی

436

2)برنامه را اجرا کنی د . حال می توانید اطلاعات مربوط به کتابی که اضافه کرده بودید را تغییر دهید و یا تغییراتی را در

قیمت آن را تغییر دهی د . Price اطلاعات مربوط به دیگر ک ت اب ها ایجاد کنی د . یک کتاب را انتخاب کرده و با استفاده از کاد ر

کلیک کنی د . به این ترتیب تغییرات مورد نظر شما در بانک اطلاعاتی ذخیره م ی شود و پیغامی Update سپس روی دکم ه ی

تیز در نوار وضعیت نمایش داده م یشود و ثبت تغییرات را اعلام می کند.

12- شکل 23

8-حذف کردن یک رکورد - مثال 23

آن ایجاد click دو بار کلیک کنید تا متد مربوط به رویدا د btnDelete 1) به قسمت طراحی فرم رفته و روی دکم ه ی

شود. سپس کد مشخص شده در زیر را در این متد وارد کنید:

private void btnDelete_Click(object sender, EventArgs e)

{

// Declare local variables and objects...

int intPosition;

SqlCommand objCommand = new SqlCommand();

// Save the current record position - 1 for the one to

// be deleted...

intPosition =this.BindingContext[objDataView].Position - 1;

// If the position is less than 0 set it to 0...

if( intPosition < 0 )

intPosition = 0;

// Set the Command object properties...

objCommand.Connection = objConnection;

objCommand.CommandText = "DELETE FROM titleauthor " +

"WHERE title_id = @title_id;" +

"DELETE FROM titles WHERE title_id = @title_id";

// Parameter for the title_id field...

objCommand.Parameters.AddWithValue("@title_id",

this.BindingContext[objDataView,"title_id"].Current);

// Open the database connection...

objConnection.Open();

// Execute the SqlCommand object to update the data...

objCommand.ExecuteNonQuery();

// Close the connection...

objConnection.Close();

// Fill the DataSet and bind the fields...

FillDataSetAndView();

BindFields();

// Set the record position

// to the one that you saved...

ADO.NET با SQL Server فصل بیست و سوم استفاده از بانک اطلاعاتی

437

this.BindingContext[objDataView].Position =

intPosition;

// Show the current record position...

ShowPosition();

// Display a message that the record was deleted...

ToolStripStatusLabel1.Text = "Record Deleted";

}

2) خوب به این ترتیب این پروژه نیز به پایان رسی د . اما به تر است قبل از اینکه از تمام شدن آن خوشحال شویم ابتدا

قابلیت جدیدی که اضافه کرد ه ایم را امتحان کنی م . برنامه را اجرا کرده و هر کتابی که م ی خواهید حذف کنید را انتخاب

که در این ب ر نامه از آن pubs کلیک کنی د . به خاطر داشته باشید که ب ا نک اطلاعاتی Delete کنید، سپس روی دکم ه ی

متصل شوند و SQL Server استفاده کرده ایم یک بانک اطلاعاتی نمونه است و ممکن است افراد دیگری نیز به این

بخواهند از آن برای ت مرینات خود استفاده کنن د . بنابراین بهتر است داد ه هایی را حذف کنیم که در قسمت قبل ایجاد

کرده بودیم . قبل از اینکه یک کتاب را ح ذ ف کنید، به شمار ه ی رکوردها در برنامه توجه کنید، سپس کتاب مورد نظر

خود را حذف کنی د . البته در این قسمت ممکن است با خطا مواجه شوید، زیرا کتابی که برای حذف انتخاب کرد ه اید

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

و حذف کنید.

13- شکل 23

-5-23 خلاصه

و SqlDataAdapter ،SqlCommand ،SqlConnection از قبیل ADO.NET در این فصل با بعضی از کلا سهای مهم

آشنا شدید و مشاهده کردیم که این کلا سها چگونه می توانند هنگام دریافت اطلاعات، وارد کردن SqlParameter

اطلاعات جدید، حذف اطلاعات جاری و یا ویرایش آنها کمک کنند. البته تمام این کلاس ها برای بان کهای اطلاعاتی مورد

ایجاد شده باشند. این کلاس ها دارای کلاس ها دارای SQL Server استفاده قرار می گیرد که بوسیله ی موتور بانک اطلاعاتی

قرار دارند. System.Data.OleDb شروع می شوند و در فضای نامی OleDb کلاس های متناطری هستند که با پیشوند

را بررسی کرده و نحوه ی استفاده System.Data از فضای نامی DataView و DataSet همچنین در این فصل کلا سهای

از آنها در یک برنامه را مشاهده کردیم و دیدیم که چگونه م یتوان با استفاده از این کلا سها اشیایی را ایجاد کرد و داد ههای

موجود در آنها را به کنترل های ساده ی موجود در فرم متصل کرد.

اسلام احمد زاده - 09177112161 - C# برنامهنویسی

438

را برای جابه جایی مابین رکوردها دیدید. در این فصل برای دسترسی به داده ها، CurrencyManager نحوه ی استفاده از

ایجاد داده های جدید، حذف داده های موجود و یا ویرایش آنها از روش های دستی استفاده کرده و کد مربوط به تمام این

موارد را خودمان در برنامه وارد کردیم

mohsen_mahyar@yahoo.com - C# برنامه نویسی

 

 

   + MOHSEN GHASEMI - ۱٠:٢٧ ‎ب.ظ ; ۱۳۸٩/٤/۳٠

فصل بیست و دوم استفاده از بانک اطلاعاتی در #C

<!-- /* Font Definitions */ @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:1; mso-generic-font-family:roman; mso-font-format:other; mso-font-pitch:variable; mso-font-signature:0 0 0 0 0 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman","serif"; mso-fareast-font-family:"Times New Roman";} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; font-size:10.0pt; mso-ansi-font-size:10.0pt; mso-bidi-font-size:10.0pt;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0; mso-gutter-direction:rtl;} div.Section1 {page:Section1;} -->

فصل بیست و دوم

  C#  استفاده از بانک اطلاعاتی در 

آنچه که در این فصل یاد خواهید گرفت:

با مفهوم بان کهای اطلاعاتی آشنا خواهید شد.

آشنا خواهید شد و از آن استفاده خواهید کرد. SQL در زبان SELECT • با دستور

کنترل های دسترسی به داده های درون بانک اطلاعاتی را بررسی خواهید کرد.

با نحوه ی استفاده از داده ها در برنامه های ویندوز آشنا خواهید شد.

2005 استفاده خواهید کرد. VS • از ویزاردهای دسترسی به اطلاعات در

-1-22 مقدمه

2005 بیشتر VS اغلب برنامه های کامپیوتری که امروزه نوشته م یشوند به نحوی با داد هها و اطلاعات مختلف کار می کنند. در

این برنامه ها، داد ههای مورد نیاز خود را در بان کهای اطلاعاتی رابطه ای نگهداری م یکنند. بنابراین در هنگام نوشتن این نوع

،SQL server برنامه ها نیاز دارید که بتوانید در برنامه ی خود با نرم افزارهای مربوط به این بانک های اطلاعاتی، مانند

کار کنید. Sybase و یا oracle ،Access

2005 ابزارهای و ویزاردهای زیادی برای متصل شدن به انواع بانک های اطلاعاتی وجود دارد. به وسیله ی این ابزارها VS در

می توانید اطلاعات خود را در درون این بان کهای اطلاعاتی قرار دهید و یا آن را از بان کهای اطلاعاتی دریافت کرده و

تغییرات مورد نظر خود را روی آنها انجام دهید. در طی این فصل سعی کنید که با این ابزارها و نحو هی کارکرد آنها در برنامه

بیشتر آشنا شوید.

درفصل بعدی تمرکز خود را روی استفاده از بانک های اطلاعاتی از طریق کدنویسی قرار خواهیم داد و مشاهده خواهیم

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

مقداری در کدنویسی بانک های اطلاعاتی تمرین کردید، خواهید دید که استفاده از کد نسبت به استفاده از ویزاردها و ابزارها

زمان بسیار کمتری را اشغال می کند.

که Microsoft Access نکته: برای انجام تمرینات و مثا لهای این فصل لازم است که نسخ هی 2000 ( و یا بالاتر) برنامه

به شمار می رود را نصب کنید. Microsoft office جزئی از برنامه ی

mohsen_mahyar@yahoo.com - C# برنامه نویسی

388

بانک اطلاعاتی چیست؟

اصولا" هر بانک اطلاعاتی شامل یک و یا چند فایل بزرگ و پیچیده است که داد هها در آن در یک قالب و فرمت ساخت یافته

ذخیره می شوند. موتور بانک اطلاعاثی معمولا به برنام های اطلاق م یشود که این فایل و یا فایلهایی و نیز داده های درون آنها

به عنوان موتور بانک اطلاعاتی استفاده خواهیم Microsoft Access را مدیریت می کند. در طی این فصل از برنامه ی

کرد.

Access اشیای موجود در

است) معمولا" از قسم تهای مختلفی مانند mdb. که پسوند آن نیز ) Access یک فایل بانک اطلاعاتی مربوط به برنام هی

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

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

سعی می کنند با ارائه دادن امکانات اضافی، به کاربران اجازه دهند با Access همین دلیل، موتورهای بانک اطلاعاتی مانند

وجود دارند، جدول ها و پرس وجوها برای نگهداری Access این اطلاعات کار کنند، در بین اشیایی که در یک بانک اطلاعاتی

داده ها و یا دسترسی به آنها به کار م یروند. دیگر اشیای یک بانک اطلاعاتی مانند فرم ها و یا گزارشات برای این است که

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

اما به هر حال به علت پیچیده بودن ساختار موتورهای بانک اطلاعاتی، کاربران معمولی حتی با استفاده از این قسمت ها نیز

نمی توانند به درستی از اطلاعات درون بانک اطلاعاتی استفاده کنند. هدف ما از نوشتن یک برنام هی بانک اطلاعاتی با

2005 و یا هر زبان برنامه نویسی دیگر این است که به کاربر اجازه دهیم به سادگی از اطلاعات درون بانک ها VS استفاده از

استفاده کند، پس در این برنامه ها فقط به اطلاعات درون یک بانک اطلاعاتی نیاز خواهیم داشت نه به قسمتهایی مانند فرم ها

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

پرس وجوها قرار می دهیم.

جدول ها

یک جدول شامل یک مجموعه از اطلاعات است که معمولا" حاوی یک و یا چند ستون و نیز یک و یا چند ردیف از داده ها

و نیز بیشتر بانک ها یا اطلاعاتی) به هر یک از این ستو نها یک فیلد گفته م یشود. همچنین هر ردیف از ) Access است. در

این اطلاعات نیز یک رکورد نامیده می شوند. هر فیلد در یک جدول از بانک اطلاعاتی، یکی از مشخصه های داده ای که در آن

در یک جدول، مشخص کنند هی نام firstName جدول ذخیره شده است را نگهداری م یکند. برای مثال، فیلدی به نام

مشترک و یا کارمندی است که اطلاعات او در آن جدول ذخیره شده است. بنابراین این فیلد یکی از مشخصه های آن کارمند

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

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

است و برای نگهداری اسامی کارمندان استفاده می شود. LastName و FirstName دو فیلد (دو ستون اطلاعات) به نامهای

به مجموع هی نام و نام خانوادگی هر کارمندی که اطلاعات او در این جدول وجود داشته باشد یک رکورد گفته م یشود. برای

و .... فیلدهای این جدول و هر ردیف از اطلاعات نیز رکوردهای آن را FirstName ،EmployeeID ،1- مثال، درشکل 22

مشخص می کند.

1- شکل 22

فصل بیست و دوم استفاده از بانک اطلاعاتی

389

پرس وجوها

نوشته شده است و برای دریافت اطلاعات از بانک SQL در هر بانک اطلاعاتی عموما" به یک سری از دستورات که زبان

اطلاعاتی و یا ایجاد تغییراتی در اطلاعات موجود در بانک به کار می رود، یک پرس وجو گفته می شود. با استفاده از

پرس وجوها می توانیم داد ههایی را درجدو لهای بانک اطلاعاتی وارد کنیم، آنها را از یک و یا چند جدول بدست آورده و یا

تغییراتی را در آنها ایجاد کنیم.

را بنویسیم SQL در یک موتور بانک اطلاعاتی به دو روش می توانیم از پر سوجوها استفاده کنیم. اول این است که یک دستور

و سپس آن را اجرا کرده و نتیج هی آن را مشاهده کنیم. روش دوم این است که همانند دیگر زبان های برنامه نویسی یک

ایجاد کنیم و سپس با فراخوانی آن زیربرنامه اطلاعاتی بدست آوریم. در برنامه هایی که SQL زیربرنامه با استفاده از دستورات

می نویسیم نیز می توانیم از یک زیربرنامه برای دسترسی به اطلاعات مورد نیاز استفاده کنیم و هم می توانیم #VC به زبان

مورد نیاز را با استفاده از برنامه به موتور بانک اطلاعاتی بفرستیم و نتایج حاصل را دریافت کرده و نمایش دهیم. SQL دستور

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

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

برخوردار است. زیرا موتور بانک اطلاعاتی م یتواند دستورات درون آن زیربرنامه را تحلیل کرده و یک روش کلی برای

سریع تر اجرا کردن آن ایجاد کند( به عبارت دیگر می تواند آنها را کامپایل کند). اما دستوراتی که به صورت عادی به موتور

بانک اطلاعاتی می دهیم تا آنها را اجرا کند و داده های مربوط را برگرداند، هر مرتبه لازم است که تفسیر شده و سپس اجرا

شوند و این مورد باعث م یشود که سرعت اجرای کمتری نسبت به زیربرنام هها داشته باشد.

SQL و دستورات آن آشنا شویم. خوشبختانه، زبان SQL برای درک بهتر مفهوم پرس وجوها، بهتر است ابتدا مقداری با زبان

نسبت به زبانهای برنامه نویسی دیگر بسیار ساد هتر است و به سرعت می توان نحوه ی استفاده از آن را یاد گرفت.

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

SQL در زبان SELECT دستور

برخلاف چیزی که ممکن است تصور کنید، زیاد مشابه زبانهای برنام هویسی که تاکنون دیده ید نیست. دستورات SQL زبان

به صورت استاندارد درآمده است. نسخه ی استاندارد این زبان که ( ANSI ) این زبان به وسیله موسسه استاندارد ملی آمریکا

نیز نامیده می شود، به وسیل هی تمام موتورهای بانک اطلاعاتی پشتیبانی م یشود. اما هر یک از این موتورهای ANSI SQL

بانک اطلاعاتی امکانات مخصوص بیشتری را نیز به این زبان اضافه کرده اند که معمولا" فقط در همان موتور بانک اطلاعاتی

قابل استفاده است.

1 Stored procedure

mohsen_mahyar@yahoo.com - C# برنامه نویسی

390

را آموختید می توانید از SQL در این است که به این وسیله، هنگامی که اصول دستورات زبان ANSI SQL مزایای یادگیری

در تمام موتورهای بانک اطلاعاتی استفاده کنید. به این ترتیب برای این که بتوانید موتور بانک SQL آنها برای برنام هنویسی

اطلاعاتی خود را تغییر دهید، فقط کافی است نحوه ی کارکرد با رابط گرافیکی آن را یاد بگیرید و سپس می توانید از

استاندارد در آن محیط نیز استفاده کنید. البته همانطور که گفتیم هر موتور بانک اطلاعاتی دارای دستورات SQL دستورات

خاص خود است که باعث افزایش کارایی و بهینه ساختن اجرای دستورات می شود. اما تاحد ممکن بهتر است از این دستورات

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

سادگی موتور بانک اطلاعاتی خود را تغییر دهید.

از تعداد کمی دستور تشکیل شده است که هر یک کار خاصی را انجام م یدهند. یکی از پرکاربردترین و مهمترین SQL زبان

است که به وسیله ی آن می توانید یک یا چند فیلد اطلاعات مربوط به یک یا چند رکورد در جدول SELECT این دستورات

فقط م یتوانید داده ها را از SELECT بانک اطلاعاتی خود را بدست آورید. البته دقت داشته باشید که به وسیل هی دستور

جداول بدست آورید، اما نمی توانید هیچ تغییری در آنها ایجاد کنید.

مشابه دستور زیر است: SQL در زبان SELECT ساده ترین دستور

SELECT * FROM Employees;

این دستور همانطور که مفهوم کلمات آن نیز مشخص می کنند، به این معنی است که اطلاعات موجود در تمام فیلدهای مربوط

به معنی تمام فیلدها است. کلمه ی SELECT را انتخاب کن. علامت * در دستور Employees به همه ی رکوردهای جدول

نیز نام جدولی در بانک اطلاعاتی است که این دستور باید بر روی آن اجرا شود. Employees

وارد شده است را Employees اگر بخواهید فقط فیلدهای مربوط به نام و نام خانوادگی افرادی که اطلاعات آنها در جدول

بدست آورید، کافی است که علامت * را با نام فیلدهای مورد نظر خود به صورت زیر عوض کنید:

SELECT [First Name], [Last Name] FROM Employees;

دقت کنید که هنگام وارد کردن این دستور حتما" باید از علامت [ ] در ابتدای نام فیلدها استفاده کنید. زیرا نام این فیلدها

با مشکل مواجه شود. استفاده از [] First Name است و باعث می شود که برنامه در تفسیر نام ( space) حاوی فضای خالی

به موتور بانک اطلاعاتی می گوید که کلمات داخل [] را به عنوان یک نام در نظر بگیرد. البته اگر نام این فیلد حاوی کاراکتر

فضای خالی نبود، می توانستید از [] استفاده نکنید.

همانند زبان انگلیسی عادی و روزمره هستند و حتی فردی که برنامه نویس SQL همانطور که مشاهده می کنید دستورات

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

استفاده کنیم. SELECT در پایان دستور WHERE هستند از جدول انتخاب شده و نمایش داده شوند، کافی است از عبارت

شروع می شوند انتخاب شوند، باید از دستور D مثلا" اگر بخواهیم در دستور قبل فقط افرادی که نام خانوادگی آنها با حروف

زیر استفاده کنیم:

SELECT [First Name], [Last Name] FROM Employees

WHERE [Last Name] LIKE ‘D*’;

صدق می کنند. بنابراین WHERE باعث می شود فقط داد ههایی از جدول انتخاب شوند که در شرط مقابل عبارت WHERE عبارت

و Last Name برود و فیلد Employees قبلی باعث می شود که موتور بانک اطلاعاتی به داخل جدول SELECT دستور

نیز به این معنی `*D` شروع می شود را انتخاب کند. عبارت D آنها با حرف Last Name تمام رکوردهایی که First Name

به این معنی است که "هر عبارتی که در آن `*D*` شروع شده است . برای مثال، عبارت D است که هر عبارتی که با حروف

وجود داشته باشد." D حرف

در آخر نیز بعد از اینکه داده های موردنظر خود را انتخاب کردید، می توانید آنها را به نحوی که تمایل دارید به صورت صعودی

ORDER ازعبارت SELECT برای کار باید در انتهای دستور First Name و یا نزولی مرتب کنید، برای مثال، براساس فیلد

استفاده کنید. BY

فصل بیست و دوم استفاده از بانک اطلاعاتی

391

SELECT [First Name], [Last Name] FROM Employees

WHERE [Last Name] LIKE ‘D*’ ORDER BY [First Name];

اجرای این دستور باعث می شود اطلاعاتی از جدول انتخاب شوند. برای مثال، خروجی این دستور م یتواند مانند زیر باشد:

Angela Dunn

David Dunstan

Zebedee Dean

همانطور که مشاهده می کنید در این قسمت از یک دستور تقریبا" کامل استفاده کردیم، اما درک آن نیز بسیار ساده بود و

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

A براساس فیلدهای رشته ای مرتب می کنید، داده ها به صورت صعودی مرتب می شوند. به این صورت که اطلاعات با حرف

در انتها نمایش داده می شوند. اما هنگامی که بخواهید اطلاعات را براساس یک فیلد عددی مرتب Z ابتدا و اطلاعات با حرف

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

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

استفاده DESC از عبارت ORDER BY که اطلاعات را به صورت نزولی مرتب کنید. برای این کارکافی است در پایان دستور

کنید. به این ترتیب داد هها به صورت نزولی مرتب خواهند شد.

SELECT [First Name], [Last Name] FROM Employees

WHERE [Last Name] LIKE ‘D*’ ORDER BY [First Name] DESC;

اجرای دستور بالا نتایجی را مشابه زیر برمی گرداند:

Zebedee Dean

David Dunstan

Angela Dunn

نکته: اگر می خواهید در دستور خود مشخصا" قید کنید که اطلاعات باید براساس صعودی مرتب شوند، م یتوانید در انتهای

استفاده کنید. البته استفاده از این عبارت الزامی نیست، زیرا به صورت پیش فرض ASC از عبارت ORDER BY دستور

اطلاعات به صورت صعودی مرتب م یشوند.

می تواند با ساختاری مشابه زیر مورد استفاده قرار بگیرد: SELECT بطور خلاصه، م یتوان گفت که دستور

SELECT select-list

FROM table-name

[WHERE search-condition]

[ORDER BY order-by-expression [ASC | DESC]]

حتما" باید لیستی از نام فیلدهای مورد نظر و یا علامت * برای select-list این عبارت به این معنی است که در قسمت

نیز باید نام جدول مورد نظر را بیاورد. می توانید از table-list انتخاب تمام فیلدها را ذکر کنید. همچنین در قسمت

search-condition خود استفاده کنید. به این ترتیب فقط داده هایی که در شرط SELECT در دستور WHERE عبارت

نیز می توانید داده ها را مرتب کنید. برای این کار باید ORDER BY صدق می کنند، انتخاب خواهند شد. با استفاده از قسمت

فیلدی که می خواهید داده ها براساس آن مرتب شوند را ذکر کنید. برای صعودی و یا order-by-expression در قسمت

در انتهای دستور استفاده کنید. DESC و یا ASC نزولی بدن مرت بسازی نیز م یتوانید ازعبارت

البته اگر بخواهید داد هها را از چندین جدول یک بانک اطلاعاتی استخراج کنید و یا براساس رابط هی خاصی به داد هها

به مقدار قابل ملاحظه ای پیچیده خواهند شد که توضیح این گونه دستورات از اهداف SQL دسترسی پیدا کنید، دستورات

این کتاب خارج است و در برنام ههای این فصل و فصل بعد نیز به آنها نیازی نخواهیم داشت.

تمرین و کار کردن با این دستورات است. قبل از ،SQL در هر حال بهترین روش برای یادگیری نحوه ی استفاده از دستورات

این که به ادامه ی فصل بپردازیم بهتر است به سوالات زیر به صورت ذهنی پاسخ دهید.

mohsen_mahyar@yahoo.com - C# برنامه نویسی

392

Price و Description ،Name بنویسیم که داده های موجود در فیلدهای SELECT • چگونه می توانید یک دستور

استخراج کند؟ Products را از یک جدول به نام

آنها Description • چگونه می توان دستور بالا را به گون های تغییر داد تا فقط داده هایی را برگرداند که در فیلد

وجود داشته باشد؟ DVD عبارت

چگونه می توان اطلاعات بالا را براساس قیمت به گونه ای مرتب کرد که اجناس گرانتر در ابتدای جدول قرار بگیرد؟

-2-22 کنترل های دسترسی اطلاعات

2005# برای دسترسی به اطلاعات و نمایش آنها سه کنترل مهم و اصلی وجود دارند که عبارتند از: C در ویژوال

2 - همانطور که در شکل 22 DataSet و BindingSource دو کنترل .DataSet و TableAdapter ،Bindingsource

نیز براساس مسیری که برای TableAdapter در جعبه ابزار وجود دارند. کنترل Data مشاهده می کنید در قسمت

دسترسی به اطلاعات درون بانک اطلاعاتی و نمایش آنها طی می کنید به صورت اتوماتیک ایجاد خواهد شد.

2- شکل 22

نکته: این کنترل ها که عموما" به عنوان کنترل های داده ای شناخته می شوند، خود فقط چندین کلاس هستند، مانند تمام

که در قسمتهای قبلی از آنها استفاده کردیم. در این فصل فقط با نحو هی استفاده از این کلاس ها در .NET کلاس های دیگر

برنامه های ویندوزی آشنا م یشویم. در فصل بعد، سعی می کنیم که کلا سهای مربوط به این کنتر لها را با جزئیات بیشتری

بررسی کنیم.

DataSet

در حقیقت همانند یک مخزن است که داده های مورد نیاز را در حافظ هی کامپیوتر نگهداری می کند. این Dataset کنترل

کنترل همانند یک موتور بانک اطلاعاتی کوچک عمل می کند که داده های مورد نیاز خود را در حافظه نگهداری م یکنند. با

که در فصل بعدی DataView استفاده از این کنترل م یتوانید داده ها را درون جدول هایی نگهداری کرده و سپس از کنترل

توضیح داده خواهد شد. به چندین روش پرس وجوهایی را روی این داد هها اجرا کنید.

از قدرت و امکانات زیادی برخورددار است. این کنترل علاو هبراین، توانایی ذخیر هی داده ها در جدول، حجم DataSet کنترل

زیادی از فراداده( اطلاعاتی درباره ی داده ها ی موجود) را نیز نگه داری می کند. این اطلاعات شامل مواردی مانند نام

جدول ها و یا فیلدها، نوع داده های موجود، اطلاعات مورد نیاز برای مدیریت داده ها و یا اطلاعاتی در رابطه با لغو کردن

تغییرات اعمال شده در داد هها می باشد.

فصل بیست و دوم استفاده از بانک اطلاعاتی

393

XML می تواند به سادگی در قالب DataSet در حافظه ذخیره می شوند. به علاوه، یک کنترل XML تمام این اطلاعات در قالب

از XML از دیسک در حافظه قرار داده شود. همچنین این کنترل م یتواند به صورت XML در دیسک ذخیره شده و یا از قالب

طریق شبکه های مختلف مانند اینترنت به برنامه های دیگر فرستاده شود و مورد استفاده قرار گیرد.

در حافظه قرار دارند، بنابراین می توانید به سادگی در بین آنها به جلو و یا عقب DataSet به علت اینکه داده های یک کنترل

حرکت کنید و یا در آنها تغییراتی را ایجاد کنید. البته این تغییرات در داد ههای موجود در حافظه اعمال می شوند و تا زمانی

که مشخص نکنید به داد های موجود در بانک اطلاعاتی منعکس نخواهند شد. در مورد این کنترل در فصل بعد بیشتر صحبت

خواهیم کرد. اما در این فصل فقط داده هایی را در آن قرار داده و سپس به وسیله ی کنترل های دیگری آن داده ها را در برنامه

نمایش خواهیم داد.

DataGridView

این کنترل برای نمایش داده های موجود در یک بانک اطلاعاتی در فرم برنامه به کار می رود. برای کار با آن کافی است آن را

به منبع داده های خود، برای مثال یکی ازجدولهای موجود در بانک اطلاعاتی، متصل کرده و سپس این کنترل را تنظیم کنید

تا آن داده ها را همانند یک جدول، یعنی ستو نها را به صورت عمودی و ردی فها را به صورت افقی نمایش دهد.

همچنین این کنترل دارای خاصیتهای زیادی است که به وسیله ی آنها می توانید ظاهر آن را تنظیم کنید تا به شکلی که مد

نظر شماست تبدیل شود. علاوه براین، به وسیل هی این کنترل م یتوانید عنوان ستونهای داد هها و یا روش نمایش آنها نیز

تعیین کنید.

BindingSource

و نیز کنترل هایی که برای (DataSet) این کنترل همانند پلی برای ایجاد ارتباط بین داد ههای موجود در منبع داد های شما

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

موجود در برنامه ی خود را نمایش دهید، و یا به هر دلیل دیگری بخواهید به آنها در منبع اطلاعاتی دسترسی داشته باشید،

این ارتباط باید از طریق این کنترل صورت بگیرد.

در فرم برنامه DataGridview را به وسیل هی یک کنترل DataSet برای مثال تصورکنید که داد ههای موجود در یک

نمایش داده اید و حال می خواهید این داده ها براساس یکی از ستونها مرتب شده و سپس نمایش داده شوند. برای این کار

DataSet می فرستد و سپس این کنترل آن را به کنترل Bindingsource این تقاضا را به کنترل DataGridView کنترل

اعلام می کند. در ادامه ی این فصل با نحو هی استفاده از این کنترل بیشتر آشنا خواهیم شد.

BindingNavigator

یک رابط گرافیکی استاندارد را برای حرکت بین رکوردهای موجود در یک بانک اطلاعاتی BindingNavigator کنترل

نمایش داده می شود. این کنترل Access ایجاد می کند. این کنترل بسیار مشابه کنترلی است که در پایین جدول در برنامه

متصل شده و از طریق آن به داد ههای موجود در BindingSource می تواند به کنترل DataGridView نیز همانند کنترل

در این کنترل کلیک کردید تا به رکورد Next برنامه دسترسی داشته باشد. به این ترتیب، برای مثال هنگامی که روی کلید

فرستاده شده BindingSource به کنترل BindingNavigator بعدی اطلاعات بروید، درخواست شما به وسیله ی

و یا منبع اطلاعاتی دیگر که در برنامه از آن استفاده می کنید) ) DataSet به کنترل BindingSource وسپس از کنترل

اعلام می شود.

TableAdapter

این کنترل در جعبه ابزار .DataAdapter تنها یک کنترل داده ای دیگر مانده است که باید در مورد آن صحبت کنیم: کنترل

وجود ندارد که بتوانید آن را همانند کنترل های قبلی بر روی فرم قرار دهید. بلکه بسته به روشی که کنترل های داده ای دیگر

را در برنامه قرار داده و آنها را تنظیم می کنید، این کنترل به صورت اتوماتیک ایجاد می شود.

mohsen_mahyar@yahoo.com - C# برنامه نویسی

394

این کنترل حاوی پرس وجو هایی برای انتخاب داده های موجود در بانک اطلاعاتی و نیز اطلاعاتی در مورد نحوه ی اتصال برنامه

به بانک است. همچنین این کنترل حاوی متدهایی است که به وسیله ی آنها می توان داده ها را از جداول بانک اطلاعاتی

قرار داد و سپس در برنامه از آن داده ها استفاده کرد. این کنترل این قابلیت را DataSet بدست آورد و در کنتر لهایی مانند

،UPDATE ای که برای انتخاب داده ها از بانک اطلاعاتی برای آن وارد م یکنید دستورات SELECT دارد که براساس دستور

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

درفصل بعد بیشتر با این کنترل آشنا خواهیم شد.

-3-22 مقید کردن داده ها

به آنها دسترسی دارید را به BindingSource مقید کردن داد هها به این معنی است که داد ههایی که به وسیله ی کنترل

یک کنترل خاص نسبت دهید. به عبارت دیگر کنترل را بتوانید به نحوی تنظیم کنید که داده های مورد نیاز خود را به

وسیله ی کنترل های دسترسی داده ها در برنامه دریافت کند و سپس آنها را به صورت اتوماتیک به کاربر نمایش دهد. به این

تقریبا" تمام کنترل ها تا #VC ترتیب کاربر می تواند آنها را مشاهده کرده و یا تغییرات موردنظر خود را در آنها اعمال کند، در

حدی اتصال به داده ها را پشتیبانی می کنند، اما بعضی از کنتر لها نیز وجود دارند که مخصوص این کار طراحی شده اند، مانند

به آنها دسترسی BindingSource در مثال بعدی اطلاعاتی که به وسیل هی کنترل .TextBox و یا DataGridView کنترل

متصل کرده و به وسیل هی این کنترل نمایش می دهیم. در بخش بعد نیز این اطلاعات را DataGridview داریم را به کنترل

در برنامه نمایش خواهیم داد. TextBox به وسیله ی کنترل

DataGridView 1- مقیدکردن داده ها به کنترل - مثال 22

ایجاد Northwind Customers DataGridview 2005 یک برنامه ی ویندوزی جدید به نام VS 1) با استفاده از

کنید.

دو بار کلیک کرده تا یک DataGridview بروید و سپس روی کنترل Data 2) با استفاده از جعبه ابزار به قسمت

به صورت اتوماتیک DataGridView Tasks نمونه از این کنترل روی فرم برنامه قراربگیرد. به این ترتیب کادر

3 نمایش داده خواهند شد. - همانند شکل 22

3- شکل 22

فصل بیست و دوم استفاده از بانک اطلاعاتی

395

کلیک کرده و سپس در این لیست روی لینک Choose DataSource 3) در این کادر، در لیست روبروی عبارت

DataSource Configuration Wizard کلیک کنید. به این ترتیب ویزارد Add Project DataSource

نمایش داده خواهد شد.

می توانید منبع داده ای مورد نظر Choose a DataSource Type 4) در صفح هی اول این ویزارد، یعنی پنجره ی

4 نیز مشاهده می کنید، در این قسمت می توانید انواع مختلفی از - خودتان را انتخاب کنید. همانطور که در شکل 22

منبع ____________های داده ای را مشخص کرده و به آنها متصل شوید. برای مثال، اگر می خواهید به یک بانک اطلاعاتی که توسط

و یا .... ایجاد می شود دسترسی داشته باشید، روی SQL Server ،Oracle ،Access نرم افزارهای مختلفی مانند

کلیک کنید. اگر می خواهید از طریق یک وب سرویس به بانک اطلاعاتی خود متصل شوید، روی Database آیکون

نیز برای دسترسی به کنترل های داده ای در لایه ی منطق objects کلیک کنید. آیکون Web Service آیکون

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

کلیک کنید. Next را انتخاب کرده و سپس روی دکم هی Database در این قسمت آیکون

4- شکل 22

کلیک کنید. New Connection روی دکمه ی Choose Your Data Connection 5) در پنجر هی

Microsoft نمایش داده خواهد شد. در این پنجره گزین هی Choose DataSource 6) به این ترتیب پنجر هی

کلیک کنید. Continue انتخاب کرده و روی دکم هی DataSource را از لیست Access Database file

در مکان نصب samples کلیک کرده و سپس به پوشه ی Browse روی دکمه ی Add Connection 7) درکادر

C:\Program 2003 در آدرس office بروید. این پوشه به صورت پیش فرض برای office برنامه ی

را Northwind.mdb قرار دارد. در این آدرس فایل Files\Microsoft Office\ Officell\Samples

Add کلیک کنید تا نام و مسیر فایل انتخابی به کادر متنی موجود در پنجره ی OK انتخاب کرده و سپس روی دکمه ی

Add Connection کلیک کنید تا کادر OK اضافه شوند. سپس در این پنجره نیز روی دکمه ی Connection

Next برگردید. در این پنجره نیز روی دکمه ی Choose Your Data Connection بسته شود و به پنجره ی

کلیک کنید.

mohsen_mahyar@yahoo.com - C# برنامه نویسی

396

به این ترتیب کارد پیغام نمایش داده خواهد شد و از شما می پرسد که فایل بانک اطلاعاتی که انتخاب کرد هاید

جزئی از پروژه نیست. آیا می خواهید این فایل به پوش هی پروژه کپی شده و از نسخ هی کپی آن استفاده شود؟ در

کلیک کنید. YES این کادر روی دکمه ی

Save the ConnectionString on the Application Configuration 8) به این ترتیب پنجره ی

کلیک کنید. Next نمایش داده می شود. در این پنجره نیز روی دکمه File

نمایش داده می شود و به شما اجازه می دهد تا Choose Your Data Objects 9) بعد از طی این مراحل پنجره ی

داده های مورد نیاز در برنامه را انتخاب کنید. در این قسمت م یتوانید انتخاب کنید که داده های مورد نیاز شما از یک

جدول درون بانک اطلاعاتی وارد برنامه شوند، با اجرای پروسیجرهای ذخیره شده در بانک اطلاعاتی ایجاد شده و

در اختیار برنامه قرار بگیرند و یا از روشهای دیگر موجود برای گردآوری داد ههای مورد نیاز استفاده شود.

کلیک کرده و سپس Views بنابراین در لیست نمایش دهند هی اشیای موجود در بانک اطلاعاتی روی علامت مثبت کنار

4گزینه ی مورد نظر را انتخاب کنید. اگر روی علامت مثبت کنار آن کلیک کنید، - ازلیست باز شده همانند شکل 22

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

کلیک کنید تا کار در این قسمت به اتمام برسد. (فرض کنید نام گزین هی انتخاب شده finish صفحه روی دکمه ی

است). CustomerQuery

به نام BindingSource یک شی از نوع ،NorthWindDataSet به نام DataSet در این لحظه، ویزارد یک شی از نوع

CustomerQueryTableAdapter به نام TableAdapter و نیز یک شی از نوع CustomerQueryBindingSource

ایجاد می کند.

5- شکل 22

نمایش DataGridView Tasks کلیک کرده تا کادر DataGridView -10 در فرم اصلی برنامه روی مثلث کوچک کنار

داده شود. به این علت که در این قسمت نمی خواهیم داده های موجود را حذف کرده، اضافه کنیم و یا تغییر دهیم، با کلیک

علامت تیک کنار آنها را حذف کنید. اما Enable Deleting و Enable Editing ،Enable Adding روی گزینه های

Enable Column می خواهیم که بتوانیم داده ها را براساس ستو نهای مورد نظر مرتب کنیم. پس روی گزینه ی

کلیک کنید تا انتخاب شود. سپس در قسمتی از نوار عنوان فرم برنامه کلیک کنید تا این پنجره پنهان شود. Reoerdering

فصل بیست و دوم استفاده از بانک اطلاعاتی

397

Fill آن را به Dock خاصیت Properties کلیک کرده و سپس با استفاده از پنجر هی DataGridView -11 روی کنترل

تغییر دهید.

به وسیله ی اطلاعات موجود در بانک اطلاعاتی پر DataGrid -12 حال برنامه را اجرا کنید. مشاهده خواهید کرد که کنترل

خواهد شد.

با کلیک روی نام هر یک از ستو نهای موجود در جدول،م یتوانید اطلاعات را بر اساس آن ستون به صورت صعودی مرتب

کنید. کلیک مجدد روی هر ستون باعث می شود که اطلاعات بر اساس آن ستون به صورت نزولی مرتب شوند. برای تشخیص

نحوه ی مرتب شدن اطلاعات نیز می توانید از جهت مثلث کوچکی که در کنار نام ستون نمایش داده می شود استفاده کنید.

همانطور که مشاهده می کنید در این قسمت توانستید بدون اینکه حتی یک خط کد در برنامه وارد کنید داد ههایی را از یک

بانک اطلاعاتی بدست آورده و آنها را نمایش دهید. تمام کدهای مورد نیاز برای این موارد به صورت اتوماتیک توسط این

ویزارد نوشته شده اند.

TextBox 2- مقید کردن داده ها به کنترل - مثال 22

ایجاد کنید. Northwind Customers BindingNavigator یک برنامه ی ویندوزی جدید به نام VS -1 با استفاده از

به برنامه ی خود اضافه کنید. سپس خاصیت ها و مکان TextBox و سه کنترل Label -2 با استفاده از کادر ابزار سه کنترل

5 شود. - این کنترل ها را به گون های تغییر داده و تنظیم کنید که فرم برنامه مشابه شکل 22

12- شکل 22

روی علامت Properties اول کلیک کنید تا انتخاب شود. سپس با استفاده از پنجر هی TextBox -3 در فرم برنامه روی

را انتخاب Text این کنترل کلیک کنید. در لیستی که نمایش داده می شود، خاصیت (DataBindings) مثبت کنار خاصیت

6 نمایش - همانند شکل 22 DataSource کرده و روی علامت مثلث کوچک مقابل آن کلیک کنید. به این ترتیب پنجره ی

DataSource کلیک کنید. تا ویزارد …Add Project DataSource داده م یشود. در این پنجره روی لینک

1 مشاهده کرده بودید نمایش داده شود. - همانند آنچه در مثال 22 ،Configuration Wizard

6- شکل 22

mohsen_mahyar@yahoo.com - C# برنامه نویسی

398

کلیک کنید. Next را انتخاب کرده و روی کلید DataBase آیکن Choose a DataSource Type -4 در پنجر هی

Add کلیک کنید تا کادر New Connection روی دکمه ی Choose Your Data Connection -5 در پنجره ی

نمایش داده شود. Connection

را انتخاب کنید و NorthWind کلیک کرده و سپس پایگاه داد هی Browse روی دکمه ی Add Connection -6 در کادر

کلیک کنید. Next روی

به این ترتیب کارد پیغامی نمایش داده خواهد شد و به شما می گوید که فایل بانک اطلاعاتی جزئی از پروژه نیست. آیا

را انتخاب کنید. Yes می خواهید این فایل به پوشه پروژه کپی شود و از نسخ هی کپی آن استفاده شود. شما

نیز روی Save the Connection String to the Application Configuration File -7 در پنجر هی

کلیک کنید. Next دکمه ی

قرار دارد، در لیست Tables روی علامت مثبت که در سمت چپ ،Choose Your DataBase Objects -8 در پنجره ی

Customers نمایش داده می شود روی گزینه ی Tables کلیک کنید. سپس در لیستی که برای Database Objects

،CompanyName کلیک کرده تا فیلدهای این جدول نیز نمایش داده شوند. در پایان نیز با کلیک کردن روی فیل دهای

کلیک کنید. Finish آنها را انتخاب کرده و سپس روی کلید ContactTitle و ContactName

قرار دارد کلیک کنید. این بار Text روی علامت مثلث کوچک که در مقابل خاصیت Properties -9 مجددا در پنجر هی

Other 7 نمایش داده م یشود. به ترتیب روی علامت مثبت کنار گزینه های - همانند شکل 22 DataSource پنجره ی

کلیک کنید. Customers و در آخر نیز NorthwindDataSet ،Project Data Sources ،Data Sources

در این Text در این قسمت کلیک کنید. به این ترتیب کادر بسته شده و خاصیت CompanyName حال روی فیلد

متصل خواهد شد. DataSet در کنترل CompanyName به فیلد TextBox

7- شکل 22

فصل بیست و دوم استفاده از بانک اطلاعاتی

399

در پنجره ی DataBindings دوم را از فرم برنامه انتخاب کرده و سپس با استفاده از قسمت TextBox -10 کنترل

را به این کادر اختصاص دهید. ContactName کلیک کنید و مشابه قسمت قبل، فیلد Text روی خاصیت Properties

سوم نیز انتخاب کرده و فیلد سوم را به آن متصل کنید. TextBox -11 مراحل قبل را برای

دوبار کلیک کرده تا یک نمونه از آن در BindingNavigator بروید و روی کنترل Data -12 حال در کادر ابزار به قسمت

فرم قرار بگیرد. این کنترل بطور اتوماتیک به بالای فرم برنامه متصل خواهد شد.

را برابر با BindingNavigator کنترل BindingSource خاصیت Properties -13 با استفاده از پنجر هی

قرار دهید. CustomersBindingSource

8 نمایش داده خواهد شد. به وسیل هی - -14 حال برنامه را اجرا کنید. مشاهده خواهید کرد که فرم برنامه همانند شکل 22

این فرم می توانید بین رکوردهای موجود در بانک اطلاعاتی جا به جا شوید. برای مثال به رکورد بعدی و یا رکورد قبلی بروید.

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

حذف خواهد شد، اما توجه کنید که این رکورد DataSet یکی از رکوردهای موجود در Delete با کلیک کردن روی دکمه ی

نیز باعث می شود یک رکورد جدید New حذف می شود نه از بانک اطلاعاتی. همچنین کلیک کردن روی دکمه ی DataSet از

نه در بانک اطلاعاتی ایجاد شود. برای اینکه تغییرات ایجاد شده در بانک اطلاعاتی اعمال شود، لازم است DataSet در

مقداری کد در برنامه وارد کنید.

8- شکل 22

mohsen_mahyar@yahoo.com - C# برنامه نویسی

400

خلاصه

برای شما معرفی شد. که مهمترین آنها SQL در این فصل با مفهوم بانک اطلاعاتی آشنا شدید و تعدادی از دستورهای

می باشد. SELECT

سپس به بررسی نحوه ی استفاده از داده های موجود در یک بانک اطلاعاتی در یک برنام هی ویندوزی پرداختیم و مشاهده

متصل کرد. با تعدادی از TextBox و یا DataGridView کردیم که چگونه م یتوان اطلاعات را به کنترل هایی مانند

کنترل های مهم و ضروری جهت دسترسی به داده های بانک اطلاعاتی آشنا شدید.

2005 داده های موجود در یک بانک VS در این فصل مشاهده کردید که چگونه می توان با استفاده از ویزاردهای موجود در

اطلاعاتی را به سرعت به کنتر لها ی موجود در فرم متصل کرد. اما در شرایطی ممکن است نیاز به کنترل بیشتر روی نحو هی

ارتباط با بانک اطلاعاتی و یا نحو هی متصل شدن کنترل ها به داده ها داشته باشید. در فصل بعد سعی خواهیم کرد که خط

مشی متفاوتی را نسبت به این فصل پیش گرفته و سعی کنیم با استفاده از برنامه نویسی، کنتر لهای یک فرم را به داد ههای

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

خواهیم کرد که چگونه م یوان از خاصی تها و یا متدهای آنها در برنامه استفاده کرد.

 

 

mohsen_mahyar@yahoo.com - C# برنامه نویسی

 

   + MOHSEN GHASEMI - ۱٢:٢٢ ‎ق.ظ ; ۱۳۸٩/٤/۳٠

فصل بیست و یکم کار با فایل هادر #C

<!-- /* Font Definitions */ @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:1; mso-generic-font-family:roman; mso-font-format:other; mso-font-pitch:variable; mso-font-signature:0 0 0 0 0 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman","serif"; mso-fareast-font-family:"Times New Roman";} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; font-size:10.0pt; mso-ansi-font-size:10.0pt; mso-bidi-font-size:10.0pt;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0; mso-gutter-direction:rtl;} div.Section1 {page:Section1;} -->

فصل بیست و یکم

C# در کار با فایل ها      

آنچه که در این فصل یاد خواهید گرفت:

کاوش ساختار فهرست، پیدا کردن فای لها و پوش ههای موجود و بررسی خصوصیات آنها

انتقال، کپی و حذف فای لها و پوش هها

خواندن و نوشتن متن در فایل ها

کنترل دسترسی به فایل ها

مایکروسافت مدل های شی زیادی برای پوشاندن این حوزه فراهم کرده اس ت . در این فصل نحو ه ی کاربرد کلا س های پایه

برای ان ج ام کارهای شرح شده در لیست قبلی را یاد م ی گیرید. کلاس های مرتبط با عملیات سیستم فایل تقریبا در NET.

هستند. System.IO فضای نامی

-1-21 مدیریت سیستم فایل

کلاس هایی که برای جستجوی سیستم فایل و انجام عملیاتی همچون انتقال، کپی کردن و حذف کردن فای ل ها هستند، در

1 نشان داده می شوند. فضای نامی هر کلاس در داخل [ ] در کنار نام کلاس نشان داده م یشود. - شکل 21

1- شکل 21

لیست زیر کار این کلا سها را شرح می دهد

mohsen_mahyar@yahoo.com - C# برنامه نویسی

364

است که از دور قابل کنترل هستند و مرت ب کردن 1 NET. کلاس پایه ی کلاس هایی از : System.MarshalByRefObject

داده های مابین دامنه های کاربردی را مجاز می دارد.

کلاس پایه که هر شی سیستم فایل را نشان می دهد. : FileSystemInfo

این کلا سها یک فایل را روی سیستم فایل نشان می دهند. :FileInfo و File

این کلا سها یک پوشه روی سیستم فایل را نشان می دهند. :DirectoryInfo,Directry

این کلاس اعضای ایستایی دارد که م یتوانند برای دستکاری اسامی مسیرها بکار روند. :Path

این کلاس مت دها و خصوصیاتی فراهم م یکند که اطلاعاتی درباره یک درایو منتخب فراهم م یکند :DriveInfo

NET. -1 کلاس های مربوط به پوشه ها و فایل ها در -1-21

در لیست قبلی دو کلاس برای نشان دادن یک پوشه و دو کلاس برای یک فایل استفاده م ی شدند. متناسب با تعداد دفعات

نیاز به دسترسی یک فایل یا پوشه، یکی از این دو نوع کلاس را بکار م یبرند.

فقط متدهای ایستا را در بر دارند و هرگز نمون ه ای از آن ایجاد نم ی شود. هر زمانی که یک مت  د عضو :File و Directory

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

یک عمل روی یک پوشه یا یک فایل انجام دهید، کاربرد این کلا س ها موثرتر است، چون آن سربار مربوط به ایجاد نمونه از

یک کلاس را صرف هجویی می کند.

را به همراه برخی از خصوصیات و File و Directory تقریبا همه متدهای عمومی :FileInfo, DirectoryIfo

پیاده سازی می کنند. اما آنها حالت شی را نشان م ی دهند و اعضای این کلاس ایستا نیستن د . قبل از public سازنده های

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

یک شی انجام دهید این کلا س ها موثر هستن د . و چون آنها اطلاعات تصدیق را در هنگام ایجاد شی سیستم فایل می خوانند،

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

فراخوانی متدها کنترل گردد.

کار م ی کنید، اما برخی از متدهای فراخوانی شده با DirectoryInfo و FileInfo در این بخش اکثراَ با کلاس

پیاده سازی می شوند( اگرچه این متدها پارامتر اضافی نیاز دارند). مثال : File و Directory کلاس های

FileInfo myFile = new FileInfo(@"C:\Program Files\My Program\ReadMe.txt");

myFile.CopyTo(@"D:\Copies\ReadMe.txt");

کد زیر نیز همان تاثیر را دارد:

File.Copy(@"C:\Program Files\My Program\ReadMe.txt", @"D:\Copies\ReadMe.txt");

ایجاد کند و آن را برای انجام FileInfo تکه کد اول زمان بیشتری برای اجرا م ی گیرد. چون نیاز دارد یک نمونه از شی

اعمال بعدی روی همان فایل آماده می سازد. اما تکه کد دوم نیازی نیست نمون های از آن شی ایجاد شود.

DirectoryInfo یا FileInfo می توانید با ردکردن یک رشته شامل سیستم فایل مورد نظر به سازنده، نمون ه ای از کلا س

ایجاد کنید. کد مربوط به ایجاد پوشه به صورت زیر است:

DirectoryInfo myFolder = new DirectoryInfo(@"C:\Program Files");

اگر مسیر مورد نظر وجود نداشته باشد، یک استثنای زمان اجرا تولید نخواهد شد، مگر اینکه بخواهید یکی از متدهای این

می توان بود یا نبود یک پوشه و فایل را فهمید. Exists شی را فراخوانی کنید. با استفاده از خصوصیت

FileInfo test = new FileInfo(@"C:\Windows");

1 Marshaling

فصل بیست و یکم کار با فای لها

365

Console.WriteLine(test.Exists.ToString());

را اجرا کنید یک ()FileInfo.Open فایل نیست و اگر بخواهید متد c:\windows است، چون false خروجی کد قبلی

استثناء رخ می دهد.

بعد از اینکه تعیین کردید شی سیستم فایل موجود است، م ی توانید اطلاعاتی درباره آن با استفاده از خصوصیات جدول زیر

بیابید.

نام خصوصیت توصیف

زمان ایجاد فایل یا پوشه CreateTime

مسیر کامل پوشه ی فایل (FileInfo فقط در ) DirectoryName

فهرست پدر یک زیر فهرست مشخص (DirectoryInfo فقط در ) Parent

آیا فایل یا پوشه مورد نظر وجود دارد Exists

پسوند فایل را بر م ی گرداند، برای پوش ه ها رشته Extension

خالی بر می گردد.

نام مسیر کامل فایل یا پوشه FullName

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

زمان آخرین تغییر فایل یا پوشه LastWriteTime

نام فایل یا پوشه Name

بخش ریشه مسیر (DirectoryInfo فقط در ) Root

اندازه فایل بر حسب بایت (FileInfo فقط در ) Length

می توانید عملیاتی روی فایل با استفاده از متدهای جدول زیر انجام دهی د.

نام هدف

یک شی FileInfo یک پوشه یا فایل خالی با نام داده شده ایجاد م ی کند. در ()Create

بر می گرداند که به شما اجازه می دهد در فایل بنویسید. Stream

فایل یا پوشه را حذف م ی کند. در پوش ه ها یک گزینه برای حذف بازگشتی وجود ()Delete

دارد .

یک فایل یا پوشه را تغییر نام یا انتقال می دهد . ()MoveTo

فقط در ) ()CopyTo

(FileInfo

فایل را کپی م ی کند. هیچ متدی برای کپ ی کردن پوش ه ها وجود ندار د . باید

پوشه ها را ایجاد کرده و فای لها را یکی یکی کپی کنید.

فقط ) ()GetDirectories

(DirectoryInfo در

بر م ی گرداند که همه پوش ه های داخل این DirectoryInfo یک آرایه از اشیا ء

پوشه را نمایش م یدهد.

بر میگرداند که همه فای ل های داخل پوشه را FileInfo فقط در یک آرایه از اشیاء )()GetFiles

mohsen_mahyar@yahoo.com - C# برنامه نویسی

366

نشان می دهد. (DirectoryInfo

()GetFileSystemInfos

(irectoryInfo (فقط در

بر م ی گردان د که همه فای ل ها DirectoryInfo , FileInfo اشیاء

وپوشه های داخل این پوشه را نشان م یدهد.

توجه: این جدول خصوصیات و متدهای اصلی را لیست م یکند.

توجه داشته باشید که جداول قبلی بیشتر خصوصیات و متدهای مربوط به خواندن و نوشتن در فای ل ها را لیست نکرد ه اند .

و ()Create ،OpenWrite() ،OpenText() ،OpenRead() ،Open() تعدادی متد با عناوین FileInfo کلاس

را بر م ی گردانند. جالب اینکه زمان ایجاد،آخرین زمان دسترسی و Stream را پیاد ه سازی می کند که اشیاء ()CreateText

آخرین زمان تغییر قابل تغییر هستند.

// displays the creation time of a file,

// then changes it and displays it again

FileInfo test = new FileInfo(@"C:\MyFile.txt");

Console.WriteLine(test.Exists.ToString());

Console.WriteLine(test.CreationTime.ToString());

test.CreationTime = new DateTime(٢٠٠١, ١, ١, ٧, ٣٠, ٠);

Console.WriteLine(test.CreationTime.ToString());

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

True

۶/۵/٢٠٠۵ ٢:۵٩:٣٢ PM

١/١/٢٠٠١ ٧:٣٠:٠٠ AM

توانایی تغییر دستی این خصوصیات ابتدا خطرناک به نظر م ی رسد، اما آن م ی تواند خیلی مفید باش د . اگر برنامه ای دارید که

یک فایل را با خواندن آن و حذف کر د ن و ایجاد یک فایل جدید با محتویات جدید تغییر م ی دهد، شاید بخواهید تاریخ ایجاد

فایل را برای تطابق با تاریخ ایجاد فایل قدیمی اصلی تغییر دهید.

Path -2 کلاس -1-21

کلاسی نیست که بخواهید نمون ه ای از آن تعریف کنی د . در عوض، متدهای ایستایی دارد که عملیات روی اسامی ،Path کلاس

در Readme.txt مسیرها را ساد ه تر م ی سازد. مثال، فرض کنید م ی خواهید نام مسیر کامل یک فایل را نمایش دهی د . فایل

است. می توانید مسیر آن را با استفاده از کد زیر بدست آورید: c:\MyDocuments پوشه

Console.WriteLine(Path.Combine(@"C:\My Documents", "ReadMe.txt"));

از قال ب های Path بسیار ساد ه تر از بررسی سمب ل های جداسازی بصورت دستی است، چون کلاس ،Path کاربرد کلاس

Net. مختلف مسیرها در سیست م عامل های مختلف آگاه اس ت . در حال حاضر، ویندوز تنها سیست م عاملی است که توسط

وفق دهد. uinx قادر است خود را با مسیرهای Path ، جابجا شود uinx روی Net. پشتیبانی می شود. اگر

کنید و خصوصیات فایل ها را ببینید. browse بخش بعدی یک مثال ارائه م یدهد که نشان می دهد چگونه فهرست ها را

File Browser -3-1-21 مثال

ارائه م ی دهد که یک واسط کا ر بردی ساده دارد و م ی تواند FileProperties این بخش یک برنامه کاربردی ساده بنام

کرده و زمان ایجاد، زمان آخرین دسترسی، زمان آخرین تغییر و اندازه فایل را ببینید. Browse سیستم فایل را

فصل بیست و یکم کار با فای لها

367

کلیک Display روش کار برنامه بصورت زیر اس ت : نام فایل یا پوشه را در کادر متنی بالای پنجره تایپ کرده و روی دکمه

می شود. اگر مسیر ی ک فایل را تایپ کنید، جرئیات آن در کادرهای متنی پایین فرم نمایش داده م ی شود و محتویات پوشه در

را نشان می دهد. FileProperties 34 برنامه کاربردی - نمایش داده می شود. شکل 2 ListBox

34- شکل 2

Up کاربر با کلیک بر روی هر پوشه در لیست سمت راست، م ی تواند به پوش ه های داخ لی حرکت کند و با کلیک بر روی دکمه

را نشان می دهد. کاربر می تواند با کلیک بر روی نام My Dcumants 34 محتویات پوشه - به پوشه پدر حرکت کند. شکل 2

آن را انتخاب کن د . این عمل خصوصیات فایل را در کادرهای متنی پایین برنامه نشان م ی دهد. شکل 34 ،ListBox فایل در

3- را ببینید.

34- شکل 3

توجه : به دلخواه م یتوانید زمان ایجاد، زمان آخرین دسترسی، زمان آخرین تغییر پوش هها را با استفاده از خصوصیات

نشان دهید. DirectoeyInfo

اسلام احمد زاده - 09177112161 - C# برنامهنویسی

368

2005 ایجاد کنید وکادرهای متنی و کادر لیست را از ناحیه کا د ر VS در Application Windows یک پروژه استاندارد

اضافه کنید و کنتر لها را به اسامی زیر تغییر نام دهید: Windows Forms ابزار

،listBoxFolders،listBoxFiles ،buttonUp ،buttonDisplay ،textBoxFolder ،textBoxInput

و textBoxLastWriteTime ،textBoxLastAccessTime،textBoxCreationTime ،textBoxFileName

textBoxFileSize

استفاده خواهید کرد. System.IO لازم است نشان دهید از فضای نامی

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.IO;

یک فیلد عضو به فرم اصلی اضافه کنید.

partial class Form١ : Form

{

private string currentFolderPath;

لازم است اداره کنند ههای رویداد را برای رویدادهای تولید شده توسط کاربر اضافه کنید. ورودی های ممکن کاربر عبارتند از:

کلیک می کند. Display • کاربر روی دکمه

کلیک می کند Files • کاربر روی نام فایل در فای لهای کادر لیست

کلیک می کند. Folders • کاربر روی نام یک پوشه در کادر لیست

کلیک می کند . Up • کاربر روی دکمه

محتویات همه کنتر ل های روی فرم را پاک م ی کند. چون خیلی از رویدادها باید قبل از انجام کار ()ClearAllFields متد

خود، همه کنترل ها را پاک کنند.

protected void ClearAllFields()

{

listBoxFolders.Items.Clear();

listBoxFiles.Items.Clear();

textBoxFolder.Text = "";

textBoxFileName.Text = "";

textBoxCreationTime.Text = "";

textBoxLastAccessTime.Text = "";

textBoxLastWriteTime.Text = "";

textBoxFileSize.Text = "";

}

پروسه ی نمایش اطلاعات یک فایل داده شده را در کادرهای متنی اداره م ی کند. این متد یک ()DisplayFileInfo متد

پارامتر می گیرد( مسیر کامل نام یک فایل را بصورت رشته می گیرد ).

protected void DisplayFileInfo(string fileFullName)

{

FileInfo theFile = new FileInfo(fileFullName);

if (!theFile.Exists)

throw new FileNotFoundException("File not found: " + fileFullName);

textBoxFileName.Text = theFile.Name;

textBoxCreationTime.Text = theFile.CreationTime.ToLongTimeString();

textBoxLastAccessTime.Text = theFile.LastAccessTime.ToLongDateString();

textBoxLastWriteTime.Text = theFile.LastWriteTime.ToLongDateString();

textBoxFileSize.Text = theFile.Length.ToString() + " bytes";

}

فصل بیست و یکم کار با فای لها

369

اگر مشکلی در پیداکردن یک فایل باشد، یک استثناء رخ م ی دهد که روال ف ر اخوانی کننده این متد، مسؤل کنترل این

محتویات یک پوشه را در دو کادر لیست نشان م ی دهد . مسیر ،()DisplayFolderList استثناء است . در نهایت، متد

کامل پوشه به عنوان پارامتر به این متد رد م یشود.

protected void DisplayFolderList(string folderFullName)

{

DirectoryInfo theFolder = new DirectoryInfo(folderFullName);

if (!theFolder.Exists)

throw new DirectoryNotFoundException("Folder not found: " + folderFullName);

ClearAllFields();

textBoxFolder.Text = theFolder.FullName;

currentFolderPath = theFolder.FullName;

// list all subfolders in folder

foreach(DirectoryInfo nextFolder in theFolder.GetDirectories())

listBoxFolders.Items.Add(nextFolder.Name);

// list all files in folder

foreach(FileInfo nextFile in theFolder.GetFiles())

listBoxFiles.Items.Add(nextFile.Name);

}

پیچیده ترین آنها اس ت . چون Display حال اداره کنند ه های رویدادها را بررسی کنی د . رویداد مربوط به کلیک روی دکمه

لازم است سه حالت ممکن برای متنی که کاربر در کادر متنی وارد کرده است را اداره کن د . برای مثال، ممکن است نام یک

فایل، مسیر کامل پوشه یا هیچکدام باشد.

protected void OnDisplayButtonClick(object sender, EventArgs e)

{

try

{

string folderPath = textBoxInput.Text;

DirectoryInfo theFolder = new DirectoryInfo(folderPath);

if (theFolder.Exists)

{

DisplayFolderList(theFolder.FullName);

return;

}

FileInfo theFile = new FileInfo(folderPath);

if (theFile.Exists)

{

DisplayFolderList(theFile.Directory.FullName);

int index = listBoxFiles.Items.IndexOf(theFile.Name);

listBoxFiles.SetSelected(index, true);

return;

}

throw new FileNotFoundException("There is no file or folder with "

+ "this name: " + textBoxInput.Text);

}

catch(Exception ex)

{

MessageBox.Show(ex.Message);

}

}

و خصوصیت FileInfo و DirectoryInfo در این کد، ابتدا به ازای متن تایپ شده توسط کاربر، به کمک نمون ه هایی از

فایل یا پوش ه بودن آن را بررسی م ی کند. اگر هیچکدام نبود، یک استثناء بروز م ی دهد. اگر فایل یا پوشه باشد، ،Exist

رویدادهایی را به ترتیب فراخوانی م یکند.

مربوط اس ت ( توسط کاربر یا از طریق برنامه نویسی Files کد زیر به اداره کنند ه ی رویداد انتخاب یک عضو در کادر لیست

رد می کند. ()DisplayFileInfo ). آن نام کامل فایل انتخابی را ایجاد کرده و به متد

protected void OnListBoxFilesSelected(object sender, EventArgs e)

{

mohsen_mahyar@yahoo.com - C# برنامه نویسی

370

try

{

string selectedString = listBoxFiles.SelectedItem.ToString();

string fullFileName = Path.Combine(currentFolderPath, selectedString);

DisplayFileInfo(fullFileName);

}

catch(Exception ex)

{

MessageBox.Show(ex.Message);

}

}

شبیه این اس ت . با این استثناء که متد Folders اداره کننده رویداد مربوط به انتخاب یک پوشه در کادر لیست

را برای بهنگام سازی محتوای کادرهای لیست فراخوانی م یکند. ()DisplayFolderList

protected void OnListBoxFoldersSelected(object sender, EventArgs e)

{

try

{

string selectedString = listBoxFolders.SelectedItem.ToString();

string fullPathName = Path.Combine(currentFolderPath, selectedString);

DisplayFolderList(fullPathName);

}

catch(Exception ex)

{

MessageBox.Show(ex.Message);

}

}

فراخوانی شود. به استثناء اینکه باید ()DisplayFolderList کلیک شود، باید متد up در نهایت، زمانیکه روی دکمه

انجام م ی شود FileInfo.DirectoryName مسیر کامل پوشه پدر را جهت نمایش بدست آوری د . این عمل با خصوصیت

که مسیر کامل پوشه پدر را بر م یگرداند.

protected void OnUpButtonClick(object sender, EventArgs e)

{

try

{

string folderPath = new FileInfo(currentFolderPath).DirectoryName;

DisplayFolderList(folderPath);

}

catch(Exception ex)

{

MessageBox.Show(ex.Message);

}

}

-2-21 انتقال، کپی و حذف فای لها

از کلا س های ()Delete ،MoveTo() همانطور که قبلا شرح داده شده، انتقال و حذف فای ل ها و پوش ه ها بوسیله متدها ی

و ()Move متدهای Directory و File انجام م ی شود. متدهای معادل آنها در کلاسهای DirectoryInfo و FileInfo

هستند . در مور د کاربرد این متدها کاملا هوشیار باشی د . این بخش کاربرد آنها را در موارد خاص با فراخوانی ()Delete

FileProperties ارائه م ی دهد. برای این کار مثال قبلی File از کلاس ()Delete و ()Copy ،Move() متدهای ایستای

بنامید . این مثال ویژگی اضافی دار د . هنگام نمایش خصوصیات FilePropertiesAndMovment را ایجاد کرده و آن را

یک فایل گزینه هایی برای حذف، انتقال یا کپی فایل به موقعیت دیگر م یدهد.

FilePeopertiesAndMovement -1 مثال -2-21

34 واسط کاربری برنامه جدید را نشان می دهد. - شکل 4

فصل بیست و یکم کار با فای لها

371

34- شکل 4

است . با استثناء اینکه سه دکمه و یک کادر FileProperyies همانطورکه می توانید ببینید، این برنامه در ظاهر شب ی ه

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

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

بطور اتوماتیک مسیر کامل فایل را در کادر متنی پایین جهت ویرایش قرار م ی دهد . FilePropertiesAndMovment

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

34 را ببینید.) - می شود. ( شکل 5

34- شکل 5

کلیک کند، عمل شروع خواهد ش د . در بعضی مواقع، عمل انجام شده باعث ایجاد یک حالت Yes زمانیکه که کاربر روی

نادرستی می شود( مثلا تغییر نام یک پوشه یا یک فایل، حذف یک پوشه ). برای حل این مشکل، همه کنتر ل ها بعد از انجام

هر کاری دوباره مقدا ردهی می شوند.

FilePropertiesAndMovment -2 بررسی کد برنامه -2-21

اضافه FileProperties برای کدنویسی این پروسه، لازم است کنتر ل های مرتبط و اداره کننده های رویداد آنها را به کد

داده شده textBoxNewPath ،buttonMoveTo ،buttonCopyTo ،buttonDelete کنید. به کنترل های جدید اسامی

است.

فراخوانی می شود را ببینید: Delete ابتدا اداره کننده ی رویدادی که زمان کلیک کاربر روی دکمه

protected void OnDeleteButtonClick(object sender, EventArgs e)

{

try

mohsen_mahyar@yahoo.com - C# برنامه نویسی

372

{

string filePath = Path.Combine(currentFolderPath,

textBoxFileName.Text);

string query = "Really delete the file\n" + filePath + "?";

if (MessageBox.Show(query,

"Delete File?", MessageBoxButtons.YesNo) == DialogResult.Yes)

{

File.Delete(filePath);

DisplayFolderList(currentFolderPath);

}

}

catch(Exception ex)

{

MessageBox.Show("Unable to delete file. The following exception"

+ " occurred:\n" + ex.Message, "Failed");

}

}

به دلیل ریسک وقوع یک استثناء قرار داده م ی شود. برای مثال، شما جواز حذف فایل را نداشته try در کد این متد بلوک

باشید یا فایل توسط پروس ه ی دیگری منتقل شده است، ولی هنوز برنامه شما آن را نشان م ی دهد. مسیر فایل مورد نظر جهت

است . textBoxFileName بسازید که شامل پوش ه ی پدر و متن داخل کادر متنی CunentParentPath حذف را از فیلد

متدهای انتقال وکپی در روشی مشابه ساختاربندی می شوند .

protected void OnMoveButtonClick(object sender, EventArgs e)

{

try

{

string filePath = Path.Combine(currentFolderPath,

textBoxFileName.Text);

string query = "Really move the file\n" + filePath + "\nto "

+ textBoxNewPath.Text + "?";

if (MessageBox.Show(query,

"Move File?", MessageBoxButtons.YesNo) == DialogResult.Yes)

{

File.Move(filePath, textBoxNewPath.Text);

DisplayFolderList(currentFolderPath);

}

}

catch(Exception ex)

{

MessageBox.Show("Unable to move file. The following exception"

+ " occurred:\n" + ex.Message, "Failed");

}

}

protected void OnCopyButtonClick(object sender, EventArgs e)

{

try

{

string filePath = Path.Combine(currentFolderPath,

textBoxFileName.Text);

string query = "Really copy the file\n" + filePath + "\nto "

+ textBoxNewPath.Text + "?";

if (MessageBox.Show(query,

"Copy File?", MessageBoxButtons.YesNo) == DialogResult.Yes)

{

File.Copy(filePath, textBoxNewPath.Text);

DisplayFolderList(currentFolderPath);

}

}

catch(Exception ex)

{

MessageBox.Show("Unable to copy file. The following exception"

+ " occurred:\n" + ex.Message, "Failed");

}

فصل بیست و یکم کار با فای لها

373

}

هنوز کارتان کامل نشده است و لا ز م است مطمئن شوید کادر متنی و دکم ه های جدید در زما نهای مناسب فعال و غیرفعال

اضافه کنید. ()DisplayFileInfo می شوند. برای فعال کردن آنها در هنگام نمایش محتویات یک فایل، کد زیر را به

protected void DisplayFileInfo(string fileFullName)

{

FileInfo theFile = new FileInfo(fileFullName);

if (!theFile.Exists)

throw new FileNotFoundException("File not found: " + fileFullName);

textBoxFileName.Text = theFile.Name;

textBoxCreationTime.Text = theFile.CreationTime.ToLongTimeString();

textBoxLastAccessTime.Text = theFile.LastAccessTime.ToLongDateString();

textBoxLastWriteTime.Text = theFile.LastWriteTime.ToLongDateString();

textBoxFileSize.Text = theFile.Length.ToString() + " bytes";

// enable move, copy, delete buttons

textBoxNewPath.Text = theFile.FullName;

textBoxNewPath.Enabled = true;

buttonCopyTo.Enabled = true;

buttonDelete.Enabled = true;

buttonMoveTo.Enabled = true;

}

داده شود. DisplayFolderList لازم است یک تغییری در

protected void DisplayFolderList(string folderFullName)

{

DirectoryInfo theFolder = new DirectoryInfo(folderFullName);

if (!theFolder.Exists)

throw new DirectoryNotFoundException("Folder not found: " + folderFullName);

ClearAllFields();

DisableMoveFeatures();

textBoxFolder.Text = theFolder.FullName;

currentFolderPath = theFolder.FullName;

// list all subfolders in folder

foreach(DirectoryInfo nextFolder in theFolder.GetDirectories())

listBoxFolders.Items.Add(NextFolder.Name);

// list all files in folder

foreach(FileInfo nextFile in theFolder.GetFiles())

listBoxFiles.Items.Add(NextFile.Name);

}

یک تابع سودمند کوچک است که کنترل های جدید را غیرفعال م یکند. DisableMoveFeatures

void DisableMoveFeatures()

{

textBoxNewPath.Text = "";

textBoxNewPath.Enabled = false;

buttonCopyTo.Enabled = false;

buttonDelete.Enabled = false;

buttonMoveTo.Enabled = false;

}

اضافه کنید تا محتوای کادرهای متنی جدید را پاک کند. ()ClearAllFields لازم است کدی به متد

protected void ClearAllFields()

{

listBoxFolders.Items.Clear();

listBoxFiles.Items.Clear();

textBoxFolder.Text = "";

textBoxFileName.Text = "";

textBoxCreationTime.Text = "";

textBoxLastAccessTime.Text = "";

textBoxLastWriteTime.Text = "";

textBoxFileSize.Text = "";

textBoxNewPath.Text = "";

}

mohsen_mahyar@yahoo.com - C# برنامه نویسی

374

در حال حاضر کد کامل است.

-3-21 خواندن و نوشتن در فایل ها

انجام DirectoryInfo و FileInfo در اصل، خواندن و نوشتن در فای ل ها بسیار ساده اس ت . با این وجود، از طریق اشی ا ء

می توانید آن کار را انجام دهید. بعدا خواهیم دید File 2,0 از طریق کلاس Net . نمی شود. در عوض با استفاده از چارچوب

نیز می توان این کار را انجام داد. Stream که از طریق شی

-1 خواندن یک فایل -3-21

ایجاد کنید که یک کادر متنی و یک دکمه و یک کادر Windows Form برای مثال خواندن یک فایل، یک برنامه کاربردی

34 ظاهر گردد - متنی چند خطی داشته باشد. فرم شما باید شبیه شکل 6

34- شکل 6

مقصود این فرم آن است که ابتدا کاربر مسیر فایل مشخص را در کادر متنی وارد کرده و روی دکمه کلیک کن د . سپس برنامه

کاربردی محتوی فایل را خوانده و در کادر متنی چند خطی نمایش دهد. کد مثال بصورت زیر می باشد:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.IO;

namespace ReadingFiles

{

partial class Form١ : Form

{

public Form١()

{

InitializeComponent();

}

private void button١_Click(object sender, EventArgs e)

فصل بیست و یکم کار با فای لها

375

{

textBox٢.Text = File.ReadAll(textBox١.Text);

}

}

}

برای خواندن محتویات buttonl_Click در ا بتدای برنامه اضافه م ی گردد و رویداد System.IO در این مثال فضای نامی

محتویات فایل را م ی خواند. این متد ابتدا فایل را باز کرده و محتویات آن را خوانده و ()File.ReadAll فایل است و متد

34 را ببینید. - سپس فایل را می بندد. مقدار بازگشتی متد، رشته ای است که همه محتویات فایل را در بر دارد. شکل 7

34- شکل 7

بصورت زیر است. File.ReadAll در مثال قبلی نشانه ی متد

File.ReadAll(FilePath);

حالت دیگر این نشانه، نحو هی کدگذاری فایل را مشخص می کند.

File.ReadAll(FilePath, Encoding);

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

انجام دهید:

File.ReadAll(textBox١.Text, Encoding.ASCII);

یک فایل باینری را باز کرده و محتویات آن را در یک آرای ه ی بایتی ReadAllBytes متدهای دیگری نیز وجود دار د . متد

می خواند. این متدها زیا د جالب نیستند، چون بیشتر هدف این است که فای ل ها خط به خط خوانده شون د . در این حالت،

استفاده کنید که این نوع عمل را مجاز م یدارد. ReadAllLines می توانید از متد

-2 نوشتن به یک فایل -3-21

2,0 بسیار ساده شده است، نوشتن در یک فایل نیز بسیار آسان اس ت . Net . همانند خواندن از فایل ها که توسط چارچوب

را برای خواندن داده فراهم ساخته است، برای ReadAllBytes و ReadAllLines ،ReadAll متدهای FCL همانطورکه

را فراهم کرده است. WriteAllLines و WriteAllBytes ،WriteAll نوشتن به یک فایل نیز متدهای

اسلام احمد زاده - 09177112161 - C# برنامهنویسی

376

را بکار برید. اما کادر متنی چند خطی را برای Windows Forms به عنوان مثالی برای نوشتن به یک فایل، همان برنامه

بصورت زیر ظاهر خواهد شد . _Click1button واردکردن اطلاعات به یک فایل بکار برید. کد رویداد

private void button١_Click(object sender, EventArgs e)

{

File.WriteAll(textBox١.Text, textBox٢.Text);

}

را تایپ کرده و در کادر متنی دوم محتوای c:\Testing.txt برنامه را ایجاد کرده و اجرا کنید . در کادر متنی اولی

نگاه کنید، \:C تصادفی تایپ کنی د . سپس روی دکمه کلیک کنی د . هیچ چیز بصری اتفاق نخواهد افتا د . اما اگر به درایو ریشه

را با محتوای مشخص شده خواهید دید. Testing.txt فایل

در موقعیت مشخص شده، فایل متنی جدیدی ایجاد م ی کند و محتوای مورد نظر را در آن نوشته و WriteAll ابتدا متد

ذخیره می کند و سپس آن را م یبندد.

اگر برنامه را مجددا اجرا کنید و فایلی همنام با قبلی ولی با محتوی جدید ایجاد کنید، هیچ اتفاق خاصی نمی افتد و فایل قبلی

رونویسی می شود. مهم است توجه کنید که محتوی جدید به فایل اضافه نم ی شود، بلکه محتوی جدید بطور کامل محتوای

فایل ها ی موجود WriteAllLines و WriteAllBytes ،WriteAll قبلی را رونویسی م ی کند. در حقیقت، همه متدها ی

را رونویسی می کنند. پس هنگام استفاده از این متدها مواظب باشید.

نشانه زیر را بکار م یبرد. WriteAll در مثال قبلی متد

File.WriteAll(FilePath, Content)

می توان کدگذاری فایل جدید را مشخص کرد.

File.WriteAll(FilePath, Content, Encoding)

WriteAllLines به شما اجازه م ی دهد محتوای یک آرای ه ی بایتی را در یک فایل بنویسید و متد WriteAllBytes متد

به شما اجازه می دهد یک آرایه از رشت هها را به یک فایل بنویسید. برای مثال، کد زیر را در اداره کننده رویداد وارد کنید.

private void button١_Click(object sender, EventArgs e)

{

string[] movies ={"Grease","Close Encounters of the Third Kind","The Day After

Tomorrow"};

File.WriteAllLines("C:\Testing.txt", movies);

}

با محتوای زیر به شما خواهد داد. Testing.txt حال روی دکمه کلیک کنید. برنامه یک فایل

Grease

Close Encounters of the Third Kind

The Day After Tomorrow

هر عنصر از آرایه ی رشته ای را در یک سطر فایل متنی م ینویسد. WriteAllLines متد

-3 جریان ها -3-21

برای انتقال داده استفاده م ی شود. داده م ی تواند در یکی از دو Stream هدف جریان 1 از زما ن های گذشته بوده اس ت . شی

جهت انتقال داده شود.

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

اگر داده از برنامه شما به یک منبع بیرونی منتقل شود، آن را نوشتن به یک جریان م یگویند.

اغلب اوقات منبع بیرونی یک فایل است، اما ضرورتا اینطور نیست. حالت های ممکن دیگر عبارتند از:

1 Stream

فصل بیست و یکم کار با فای لها

377

خواندن و نوشتن روی شبکه با استفاده از پروتکل شبکه

( pipe ) • خواندن و نوشتن به یک لوله نا مگذاری شده

خواندن و نوشتن فضایی از حافظه

تهیه کرده اس ت . System.IO.MemoryStream برای نوشتن و خواندن از حافظه بنام Net. مایکروسافت یک کلاس پای ه ی

داده شبکه را اداره می کند. کلاس پایه جریان برای خواندن و System.Net.Sockets. NetworkStream کلاس

یک کلاس برای آن ایجاد کنی د . جریان هیچ Stream نوشتن در لول ه ها وجود ندارد، ولی م ی توانید با ار ث بری از کلاس کلی

فرضی درباره طبیعت منبع خارجی در نظر نم یگیرد.

منبع خارجی م ی تواند یک متغیر در داخل ک د خودتان باش د . این پارادوکس است، اما تکنیک کاربرد جریا ن ها برای انتقال

شبیه این را برای تبدیل انواع داد ه ای صحیح c داده مابین متغیرها، م ی تواند در هنگام تبدیل انواع داد ه ای مفید باش د . زبان

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

این است که با DirectoryInfo یا FileInfo مزیت وجود یک شی مجزا برای انتقال داده به جای استفاده از کلا س های

StringWriter, متمایز کردن انتقال داده از منبع داده خاص، جابجا کردن منابع داده بسیار آسان اس ت . کلاس های

بخشی از همان درخت وارثت هستند که بعدا برای خواندن یا نو ش تن در فای ل های متنی با عنوان کلا سهای StringReader

استفاده خواهند شد. StreamWriter,StreamReader

نشان می دهد. System.IO 34 سلسه مراتب واقعی کلا سهای مرتبط با جریان را در فضای نامی - شکل 8

34- شکل 8

تا آنجا که به خواندن ونوشتن فایل ها اهمیت داده می شود، کلا سهای که بیشتر برای ما اهمیت دارند، عبارتند از:

این کلاس قصد دارد داد ه های دودویی را در یک فایل دودویی خوانده یا بنویسی د . با این وجود م ی توانید آن :FileStream

را برای خواندن یا نوشتن هر فایلی بکار برید.

این کلا سها مخصوصا برای خواندن و نوشتن فایل های متنی طراحی شده اند. :StreamWriter,StreamReader

در مثا ل های ما استفاده نم ی شوند، آنها نیز م ی توانند مفید باشی د . در BinaryWriter,BinaryReader اگرچه کلاس های

واقع این کلا س ها جریا ن ها را پیاد ه سازی نمی کنند، اما قادر هستند بست ه بندی اشیاء دیگر جریان را فراهم کنن د . کلاس های

دستورات قال ب بندی اضافی برای داد ه های دودویی را فراهم م ی کنند، که به شما اجازه BinaryWriter,BinryReader

34 را ببینید. - را به جریان مرتبط نوشته یا از آن بخوانی د. شکل 9 #c می دهد محتوی متغیرهای

34- شکل 9

mohsen_mahyar@yahoo.com - C# برنامه نویسی

378

تفاوت مابین کاربرد این کلاس ها یا کاربرد اشیاء جریان اصلی این است که اشیاء جریان پایه با بای تها کار می کنند. برای

را در یک فایل باینری بنویسید. اگر بخواهید از کلاس جریان معمولی Long مثال: فرض کنید م یخواهید یک متغیر از نوع

BinaryWriter از کلاس Write استفاده کنید، باید هر هشت بایت را بطور صریح در آن بنویسید، ولی با استفاده از متد

می توان این متغیر را یکجا به عنوان پارامتر به آن ارسال کرد تا در فایل باینری نوشته شود و بطور مشابه متد

می ریزد. Long 8 بایت از جریان استخراج کرده ودر متغیر از نوع ،BinaryReader.Read()

-4 جریان های بافر شده -3-21

به دلیل بهر ه روی، خروجی د ر زمان خواندن و یا نوشتن فایل، بافر م ی شود. بدین معنی که اگر برنام ه ی شما بخواهد دوبایت

بعدی یک جریان فایل را بخواند، جریان مربوطه درخواست خود را به سیست م عامل رد م ی کند. سپس سیستم عامل به جای

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

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

بافر استفاده خواهد کرد.

-5 خواندن و نوشتن در فایل های دودویی -3-21

انجام شود. FileStream خواندن و نوشتن در فای لهای دودویی می تواند از طریق کلاس

FileStream کلاس

برای خواندن یا نوشتن در فای ل ها استفاده م ی شود . به منظور ایجاد یک شی FileStream یک نمونه از کلاس

چهار تکه اطلاعات لازم دارید. ،FileStream

فایلی که می خواهید به آن دسترسی کنید. : File •

شیوه ی بازکردن فایل را مشخص م ی کند. برای مثال، آیا شما قصد دارید یک فایل جدید ایجاد کنید یا فایل : Mode •

موجود را باز کنید؟ و اگر فایل موجود را باز کردید قصد دارید اطلاعات آن رونویسی شوند یا اطلاعات جدید به آن

اضافه گردند ؟

نحوه ی دسترسی شما به فایل را مشخص م ی کند. برای مثال م ی خواهید یک فایل را بخوانید یا بنویسید : Access •

یا هردو کار را انجام دهید.

مشخص می کند دسترسی به این فایل منحصر است یا اجاره م ی دهید بطور همزمان جریان های دیگر نیز : Share •

به این فایل دسترسی داشته باشند و اینکه دسترسی جریا نهای دیگر خواندن و نوشتن یا هر دو می تواند باشد.

Net. بخش اول اطلاعات رشت ه ای است که نام و مسیر کامل فایل را شامل اس ت . سه بخش باقیمانده بوسیله انواع شمارشی

نمایش داده می شوند. مقادیر این انواع شمارشی در جدول زیر FileMode , FileShare,FileAccess بنام های

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

نوع شمارشی مقادیر

Append-Create-CreateNew-Open-OpenorCreate- FileMode

Truncate

Read-ReadWrite-Write FileAccess

فصل بیست و یکم کار با فای لها

379

Inheritable-None-Read-ReadWrite-Write FileShare

و Open ،Append ، اگر مد یک فایل با حالت آن ناسازگار باشد، استثنا ء هایی روی م ی دهد. اگر فایل وجود نداشته باشد

به یک استثناء منجر م ی شود . انواع شمارشی CreateNew ، استثناء تولید م ی کنند و اگر فایل موجود باشد Truncate

ترکیب کنید. (|) or بیتی هستند و م یتوانید مقادیر آنها را با عملگر بیتی FileShare,FileAccess

چندین سازنده دارد. سه سازنده ی ساده آن بصورت زیر کار م یکنند: FileStream

// creates file with read-write access and allows other streams read access

FileStream fs = new FileStream(@"C:\C# Projects\Project.doc",

FileMode.Create);

// as above, but we only get write access to the file

FileStream fs٢ = new FileStream(@"C:\C# Projects\Project٢.doc",

FileMode.Create, FileAccess.Write);

// as above but other streams don't get

// fs٣ is open

FileStream fs٣ = new FileStream(@"C:\C# Projects\Project٣.doc",

FileMode.Create, FileAccess.Write, FileShare.None);

های این سازند ه ها روی مقادیر پی ش فرض پارامتر سوم و چهارم تاثیر overload ، همانطور که این کد نشان م ی دهد

FileInfo ایجاد یک جریان فایل از یک نمونه .(FileShare.Read ,FileAccess.ReadWrite) می گذارند

امکان پذیر است.

FileInfo myFile۴ = new FileInfo(@"C:\C# Projects\Project۴.doc");

FileStream fs۴ = myFile۴.OpenRead();

FileInfo myFile۵= new FileInfo(@"C:\C# Projects\Project۵doc");

FileStream fs۵ = myFile۵.OpenWrite();

FileInfo myFile۶= new FileInfo(@"C:\C# Projects\Project۶doc");

FileStream fs۶ = myFile۶.Open(FileMode.Append, FileAccess.Write,

FileShare.None);

FileInfo myFile٧ = new FileInfo(@"C:\C# Projects\Project٧.doc");

FileStream fs٧ = myFile٧.Create();

یک جریان با دسترسی فقط خواندنی به یک فایل موجود تهیه م ی کند. در حالی که متد ()FileInfo.OpenRead متد

پارامترهای مد، حالت و ()FileInfo.Open دسترسی خواندن و نوشتن به شما م ی دهد. متد FileInfo.OpenWrite

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

fs.Close();

بستن یک جریان، منابع تخصیص یافته به آن را آزاد م ی کند و به برنام ه های دیگر اجازه م ی دهد تا جریا ن های دیگر را روی

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

چند متد برای انجام اینکار پیاده سازی می کند. FileStream

ساده ترین راه خ و اندن داده اس ت . آن یک بایت از جریان را م ی گیرد و نتیجه را به یک مقدار صحیح مابین 0 ReadByte متد

تا 255 قالب بندی می کند. اگر به انتهای جریان رسیده باشد، مقدار 1- بر می گرداند.

int NextByte = fs.ReadByte();

را فراخوانی کنی د . تعداد معینی بایت را خوانده و Read اگر قصد دارید در یک لحظه چندین بایت را بخوانید، م ی توانید متد

تعداد بای ت های واقعا خوانده شده را بر م ی گرداند. اگر مقدار صفر برگرداند، در انتهای ()Read در یک آرایه قرار م ی دهد. متد

قرار می دهد. ByteArray جریان هستید. دستور زیر داده ها را خوانده و در یک آرای هی بایتی به نام

int nBytesRead = fs.Read(ByteArray, ٠, nBytes);

پارامتر دوم یک آفست است که محل شروع پرکردن خان ه های آرایه را مشخص م ی کند و پارامتر سوم تعداد بای ت ها جهت

خواندن است.

mohsen_mahyar@yahoo.com - C# برنامه نویسی

380

یک بایت ()WriteByte متد .()Write و ()WriteByte: اگر بخواهید داده ها را در یک فایل بنویسید، دو متد وجود دار د

را به جریان م ینویسد.

byte NextByte = ١٠٠;

fs.WriteByte(NextByte);

با مقادیر خاص مقداردهی ByteArray یک آرایه از بای ت ها را م ی نویسد. برای مثال، اگر آرایه Write از طرفی دیگر، متد

اول آن به فایل بکار برید: nByte اولیه شده باشد، می توانیم کد زیر را برای نوشتن

fs.Write(ByteArray, ٠, nBytes);

-6 خواندن ونوشتن در فای لهای متنی -3-21

StreamReader کلاس

خیلی ساد هتر از ایجاد StreamReader برای خواندن فای ل های متنی استفاده م ی شود. ایجاد یک نمونه StreamReader

لازم نیس ت . نیازی نیست نوع دسترسی و مد فایل FileStream است، چون بعضی ا ز گزینه های FileStream یک نمونه

مشخص گردد، چون به طور پی شفرض مشخص است.

لازم است متدهای کد گذاری مختلف را بدانید تا در آغاز کار با فایل نوع کدگذاری را مشخص کنید.

می توانید به جای تهیه نام فایل، ارجاعی به یک جریان دیگر تهیه کنید.

تعداد StreamReader ، می تواند برای خواندن و پردازش داده از هر نوع منبع بکار بر د . نتیجه اینکه StreamReader

یک ارجاع ()OpenText و ()CreateText همچون FileInfo زیادی سازنده دارد و مجموعه ای از متدهای

به صورت زیر هستند: StreamReader برمی گرداند. چند تا از سازند ههای StreamReader

StreamReader sr = new StreamReader(@"C:\My Documents\ReadMe.txt");

StreamReader sr = new StreamReader(@"C:\My Documents\ReadMe.txt",Encoding.UTF٨);

است FileStream یک نمونه از fs با فرض اینکه

FileStream fs = new FileStream(@"C:\My Documents\ReadMe.txt",

FileMode.Open, FileAccess.Read, FileShare.None);

StreamReader sr = new StreamReader(fs);

باشد FileInfo یک نمونه از myfile درصورتی که

FileInfo myFile = new FileInfo(@"C:\My Documents\ReadMe.txt");

StreamReader sr = myFile.OpenText();

آن را ببندید. StreamReader بعد از استفاده FileStream مانند

StreamReader متدهای کلاس

خط جاری را تا انتها خوانده و در یک رشته بر م یگردد. :()ReadLine

string nextLine = sr.ReadLine();

از محل جاری تا انتهای فایل را خوانده و در یک رشته بر می گرداند. :()ReadToEnd

string restOfStream = sr.ReadToEnd();

می تواند برای خواندن یک یا چند کاراکتر استفاده شود . :()Read

int nextChar = sr.Read();

// to read ١٠٠ characters in.

int nChars = ١٠٠;

char [] charArray = new char[nChars];

int nCharsRead = sr.Read(charArray, ٠, nChars);

فصل بیست و یکم کار با فای لها

381

تعداد کارکترهای واقعا خوانده شده است. nCharRread تعداد کارکترهای درخواستی است و nChars

StreamWriter کلاس

کار م ی کند. به استثناء اینکه، فقط م ی توانید برای نوشتن یک فایل بکار بری د .حالتهای ممکن StreamReader اساسا همانند

به صورت زیر هستند. StreamWriter سازنده ی

StreamWriter sw = new StreamWriter(@"C:\My Documents\ReadMe.txt");

8 است . اگر بخواهید نحو ه ی کدگذاری را مشخص کنید، م ی توانید از سازند ه ی زیر UTF نحوه ی کدگذاری بطور پی ش فرض

استفاده کنید. پارامتر دوم می گوید: آیا فایل برای اضافه کردن داده ها باز شود یا نه.

StreamWriter sw = new StreamWriter(@"C:\My Documents\ReadMe.txt", true,

Encoding.ASCII);

باشد: FileStream یک نمونه از fs در صورتیکه

FileStream fs = new FileStream(@"C:\My Documents\ReadMe.txt",FileMode.CreateNew,

;(FileAccess.Write, FileShare.Read

;(StreamWriter sw = new StreamWriter(fs

باشد: FileInfo نمونه ای از myFile اگر

FileInfo myFile = new FileInfo(@"C:\My Documents\NewFile.txt");

StreamWriter sw = myFile.CreateText();

باید آن را ببندید. ،StreamWriter همانند دیگر کلاس های جریان، بعد از استفاده

StreamWriter متدهای کلاس

با استفاده از این متد می توانید یک کارکتر یا یک رشته یا یک آرایه کارکتری را به جریان بنویسید. :()Write متد

string nextLine = "Groovy Line";

sw.Write(nextLine);

char nextChar = 'a';

sw.Write(nextChar);

char [] charArray = new char[١٠٠];

// initialize these characters

sw.Write(charArray);

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

int nCharsToWrite = ۵٠;

int startAtLocation = ٢۵;

char [] charArray = new char[١٠٠];

// initialize these characters

sw.Write(charArray, startAtLocation, nCharsToWrite);

CryptoStream -7 رمزنگاری با کلاس -3-21

-4-21 خواندن اطلاعات درایو

2,0 توانایی خواندن اطلاعات یک درایو خاص را معرفی م یکند . این با Net . علاوه بر کار با فای لها و فهرس تها، چارچوب

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

پویش کند و سپس اطلاعات دقیق در مورد هر درایو را در اختیار شما قرار دهد.

.(10- ساده دارد(همانند شکل 21 ListBox ساده ایجاد کنید که یک Windows Form مثال: یک برنامه

mohsen_mahyar@yahoo.com - C# برنامه نویسی

382

10- شکل 21

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

داده خواهد شد.

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.IO;

namespace DriveInfo

{

partial class Form١ : Form

{

public Form١()

{

InitializeComponent();

}

private void Form١_Load(object sender, EventArgs e)

{

DriveInfo[] di = DriveInfo.GetDrives();

foreach (DriveInfo itemDrive in di)

{

listBox١.Items.Add(itemDrive.Name);

}

}

private void listBox١_SelectedIndexChanged(object sender, EventArgs e)

{

DriveInfo di = new DriveInfo(listBox١.SelectedItem.ToString());

MessageBox.Show("Available Free Space: " + di.AvailableFreeSpace + "\n"

+

"Drive Format: " + di.DriveFormat + "\n" +

"Drive Type: " + di.DriveType + "\n" +

"Is Ready: " + di.IsReady.ToString() + "\n" +

"Name: " + di.Name + "\n" +

"Root Directory: " + di.RootDirectory + "\n" +

"ToString() Value: " + di.ToString() + "\n" +

"Total Free Space: " + di.TotalFreeSpace + "\n" +

"Total Size: " + di.TotalSize + "\n" +

"Volume Label: " + di.VolumeLabel.ToString(), di.Name +

" DRIVE INFO");

}

}

}

یک لیست DriveInfo با استفاده از کلاس _Load1Form است . در رویداد System.IO اولین مرحله معرفی فضای نامی

انجام م ی شود، ()DriveInfo.GetDrives از همه ی درایوهای موجود روی سیستم تهیه کنی د . این عمل با استفاده از متد

فصل بیست و یکم کار با فای لها

383

ListBox می توانید آنها را یافته و به foreach بر م ی گرداند و با استفاده از حلق ه ی DriveInfo که یک آرایه از اشیاء

11 تولید می کند. - اضافه کنید. این کار چیزی شبیه شکل 21

11- شکل 21

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

جزئیات درایو انتخاب شده است نمایش داده م یشود.

-5-21 امنیت فایل

های فایل ها، فهرست ها نبود . بنابراین ACL 1,1/1,0 اولین بار معرفی شد. هیچ روش ساده برای کار با Net . زمانیکه چارچوب

ها را با یک ACL 2,0 کار با Net . ها به این عمل دسترسی داشت. در حال حاضر نسخه COM لازم بود با کدنویسی پیچید هی

ساده تر کرده اس ت . با این فضای ن  امی جدید، دستکاری System.Security.AccessControl فضای نامی جدید

و غیره امکان پذیر Active Directory تنظیمات امنیت فای لها، فهرست ها، کلیدهای ریجستری، اشتراک شبکه، اشیاء

است.

های یک فایل ACL -1-5-21 خواندن

یک فای ل خاص را نشان ACL با یک مثال ساده این مطلب را ارائه م ی کنیم. برنامه ی زیر یک برنامه کنسولی است که اطلاعات

می دهد.

using System;

using System.Collections.Generic;

using System.Text;

using System.IO;

using System.Security.AccessControl;

namespace ConsoleApplication١

{

class Program

{

static string myFilePath;

static void Main(string[] args)

{

Console.Write("Provide full file path: ");

myFilePath = Console.ReadLine();

try

{

using (FileStream myFile = new FileStream(myFilePath,

FileMode.Open, FileAccess.Read))

{

FileSecurity fileSec = myFile.GetAccessControl();

foreach (FileSystemAccessRule fileRule in

fileSec.GetAccessRules(true, true,

typeof(System.Security.Principal.NTAccount)))

{

mohsen_mahyar@yahoo.com - C# برنامه نویسی

384

Console.WriteLine("{٠} {١} {٢} access for {٣}", myFilePath,

fileRule.AccessControlType == AccessControlType.Allow ?

"provides" : "denies",

fileRule.FileSystemRights,

fileRule.IdentityReference.ToString());

}

}

}

catch

{

Console.WriteLine("Incorrect file path given!");

}

Console.ReadLine();

}

}

}

اس ت . این عمل دسترسی به کلاسهای System.Security.AccessControl اولین مرحله ارجاع به فضای نامی

FileStream ر ا به شما خواهد دا د . بعد از اینکه فایل خاص در یک شی FileSystemAccessRule و FileSecurity

بدست م ی آید. این اطلاعات در یک کلاس File روی شی ()GetAccessControl های فایل از طریق متد ACL . قرار گرفت

قرار م یگیرند. این کلاس قوانین دسترسی را در بر دارد. هر قانون دسترسی با یک شی FileSecurity

نمایش داده می شود. این مثال را اجرا کرده وخروجی آ ن را مشاهده کنید. FileSystemAccessRule

استفاده کنید DirectoryInfo از FileStream های یک فهرست شبیه فایل است. فقط به جای شی ACL خواندن

های یک فایل ACL -2-5-21 اضافه کردن و حذف

های یک منبع با استفاده از اشیاء استفاده شده در مثا ل های قبلی امکا ن پذیر است . کد زیر مثال قبلی خواندن ACL دستکاری

های یک فایل خاص خوانده شده، تغییر یافته و مجددا خوانده م یشود. ACL های یک فایل را تغییر می دهد. در این مثال ACL

try

{

using (FileStream myFile = new FileStream(myFilePath,

FileMode.Open, FileAccess.ReadWrite))

{

FileSecurity fileSec = myFile.GetAccessControl();

Console.WriteLine("ACL list before modification:");

foreach (FileSystemAccessRule fileRule in

fileSec.GetAccessRules(true, true,

typeof(System.Security.Principal.NTAccount)))

{

Console.WriteLine("{٠} {١} {٢} access for {٣}", myFilePath,

fileRule.AccessControlType == AccessControlType.Allow ?

"provides" : "denies",

fileRule.FileSystemRights,

fileRule.IdentityReference.ToString());

}

Console.WriteLine();

Console.WriteLine("ACL list after modification:");

FileSystemAccessRule newRule = new FileSystemAccessRule(

new System.Security.Principal.NTAccount(@"PUSHKIN\Tuija"),

FileSystemRights.FullControl,

AccessControlType.Allow);

fileSec.AddAccessRule(newRule);

File.SetAccessControl(myFilePath, fileSec);

foreach (FileSystemAccessRule fileRule in

fileSec.GetAccessRules(true, true,

typeof(System.Security.Principal.NTAccount)))

{

فصل بیست و یکم کار با فای لها

385

Console.WriteLine("{٠} {١} {٢} access for {٣}", myFilePath,

fileRule.AccessControlType == AccessControlType.Allow ?

"provides" : "denies",

fileRule.FileSystemRights,

fileRule.IdentityReference.ToString());

}

}

}

فایل اضافه م ی شود. این عمل با استفاده از شی ACL در این مثال یک قانون دسترسی جدید به

جدی  د ایجاد شده و دسترسی NTAccount انجام م ی شود. در اینجا یک نمونه از شی FileSystemAccessRule

برای تخصیص قانون FileSecurity کلاس AddAccessRule این فایل به آن داده م ی شود. سپس متد FullControl

را به یک فایل تخصیص FileSecurity یک نمونه File از شی SetAccessControl جدید استفاده م ی شود. متد

می دهد.

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

کافی است در کد قبلی تغییر زیر را انجام دهید. به جای دستور ،ACL برای حذف یک قانون از لیست

fileSec.AddAccessRule(newRule);

کد زیر را بنویسید:

fileSec.RemoveAccessRule(newRule);

-6-21 خلاصه

هستند. System.IO − کلاس های مرتبط با عملیات سیستم فایل تقریبا در فضای نامی

فقط متدهای ایستا را در بر دارند و هرگز نمون های از آن ایجاد نمی شود File و Directory − کلاس های

()Create ،OpenWrite() ،OpenText() ،OpenRead() ،Open() تعدادی متد با عناوین FileInfo − کلاس

را بر می گردانند. Stream را پیاد هسازی می کند که اشیاء ()CreateText و

عملیات روی اسامی مسیرها را ساد هتر می سازد. Path − کلاس

و FileInfo از کلا سهای ()Delete ،MoveTo() − انتقال و حذف فای لها و پوشه ها بوسیله متدهای

انجام می شود. DirectoryInfo

محتویات فایل را م یخواند. ()File.ReadAll − و متد

در موقعیت مشخص شده، فایل متنی جدیدی ایجاد می کند و محتوای مورد نظر را در آن WriteAll − ابتدا متد

نوشته و ذخیره می کند و سپس آن را م یبندد.

برای انتقال داده استفاده می شود. داده می تواند در یکی از دو جهت انتقال داده شود. Stream − شی

انجام شود. FileStream − خواندن و نوشتن در فایل های دودویی می تواند از طریق کلاس

برای خواندن فایل های متنی استفاده می شود StreamReader −

می تواند سیستم را جهت بدست آوردن درایوهای آن پویش کند و سپس اطلاعات دقیق در DriveInfo − کلاس

مورد هر درایو را در اختیار شما قرار دهد.

mohsen_mahyar@yahoo.com - C# برنامه نویسی

386

ها را با یک فضای نامی جدید ACL 2,0 کار با Net . − در حال حاضر نسخه

ساده تر کرده است. System.Security.AccessControl

 

mohsen_mahyar@yahoo.com - C# برنامه نویسی

 

   + MOHSEN GHASEMI - ۸:٥٢ ‎ب.ظ ; ۱۳۸٩/٤/٢٩

فصل بیستم دستکاری متن در #C

<!-- /* Font Definitions */ @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:1; mso-generic-font-family:roman; mso-font-format:other; mso-font-pitch:variable; mso-font-signature:0 0 0 0 0 0;} @font-face {font-family:Tahoma; panose-1:2 11 6 4 3 5 4 4 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:1627400839 -2147483648 8 0 66047 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman","serif"; mso-fareast-font-family:"Times New Roman";} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:Calibri; mso-fareast-theme-font:minor-latin; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:Arial; mso-bidi-theme-font:minor-bidi;} .MsoPapDefault {mso-style-type:export-only; margin-bottom:10.0pt; line-height:115%;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 72.0pt 72.0pt 72.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

فصل بیستم

C # دستکاری متن در

آنچه که در این فصل یاد خواهید گرفت:

یک کاراکتر را به صورت یک کاراکتر یونیکد 16 بیتی ذخیره می کند. .NET ، کاراکترها و یونیکد 1: به طور پی شفرض 􀂃

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

عنوان محلی کردن 2 بیان م یشود.

رشته ها تغییرناپذیر هستند. برای کاربرد مؤثر رشت هها، فهم معنی آنها و اینکه چگونه .NET در :String مروری بر 􀂃

تغییرناپذیری، عملیات رشته ها را تحت تأثیر قرار می دهد، ضروری است.

تکنیک های فرمت دهی اعداد و تاریخ را پشتیبانی می کند. .NET ، علاوه بر عملیات پای های رشته :String عملیات 􀂃

این کلاس یک روش مؤثر برای الحاق رشت هها فراهم می سازد. :StringBuilder 􀂃

یک موتور برای پارس کردن، تطابق و استخراج مقادیر از یک رشته بکار ،.NET در Regex عبارات منظم: کلاس 􀂃

می برد.

را معرفی می کند. موضوعات این فصل شامل کاربرد متدهای .NET این فصل توانای یهای اداره کردن رشته بوسیلة کلا سهای

اعداد و تاری خها را در String.Format جهت استخراج و دستکاری محتوای رشته است. کاربرد متد String پایه

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

را در بر دارد و غیره. JIT بهینه سازی کاربرد رشته های حرفی در کامپایلر

-1-20 کاراکترها و یونیکد

یکی از رویدادهای مهم در محاسبات، معرفی مجموعه کاراکتر هفت بیتی اسکی به عنوان شمای کدگذاری استاندارد جهت

تعیین منحصر به فرد کاراکترهای الفبایی و سمبل های مشترک دیگر است. آن بر اساس الفبای لاتین بوده و 128 کاراکتر را

تعداد کاراکترها را دو برابر کرده و سمب لهای واحد پول و الفبای اروپایی را به آن اضافه کرد. ANSI شامل است. استاندارد

چون آن بر اساس کاراکترهای لاتین است، تعدادی شمای کدگذاری برای نمایش کاراکترهای غیر لاتین همچون عربی، فارسی

و یونانی ایجاد شده است.

1 Unicode

2 Localization

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

334

ائتلاف بین المللی به دلیل نیاز به یک شمای کدگذاری جهانی، مشخصه ی یونیکد را پیشنهاد دادند. در حال حاضر آن یک

نوع برنامه و نوع زبان ، PlatForm استاندارد جهانی است که برای هر کاراکتر یک عدد منحصر به فرد تعریف می کند. نوع

مهم نیست.

-1-1-20 یونیکد

به طور کامل استاندارد یونیکد را پشتیبانی می کند. نمایش داخلی یک کاراکتر، یک عدد صحیح بدون علامت 16 بیتی .NET

است، که شمای کدگذاری یونیکد را پیروی می کند. یک کاراکتر دو بایتی می تواند 65535 مقدار مختلف ارائه دهد. شکل

1-20 نشان می دهد چرا دو بایت نیاز است.

1- شکل 20

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

مقدار دهدهی 75 می تواند در یک بایت قرار گیرد. بیت های بی نیاز صفر قرار داده می شوند. با این وجود سه کاراکتر بعدی

مقادیری در محدودة 310 تا 56609 دارند که حداقل به دو بایت حافظه نیاز دارند.

کاراکترهای یونیکد یک مشخصه ی منحصر به فرد متشکل از یک نام و مقدار دارند. نسخه جاری یونیکد 96382 کاراکتر

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

اشکال جغرافیایی، الفباء نابینایان و کاربردهای دیگر را شامل هستند. ،OCR ، ریاضی، موزیک

چون 16 بیت نمی تواند 100000 کاراکتر جهانی را پشتیبانی کنند، برای بعضی از مجموعه کاراکترها بایتهای بیشتری مورد نیاز

است. راه حل یونیکد، مکانیزم تعریف یک کاراکتر با دو مجموعة 16 بیتی است. این زوج کد، یک زوج جانشین 1نامیده

می شوند. جانشین بالا و پایین یک کاراکتر انتزاعی 32 بیتی را به یک 16 بیتی نگاشت می کنند. این روش بیش از 100000

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

واقعی اشتباه نم یشوند.

.NET و کلا سهای API به عنوان یک توسعه دهنده، می توانید جزئیات کاراکترهای 16 یا 32 بیتی را در نظر نگیرند، چون

جزئیات اصلی نمایش کاراکترهای یونیکد را اداره می کنند. اما زمانیکه می خواهید یک رشته را به صورت بایت به بایت در یک

یک شی خاص برای طی کردن بایت ها فراهم می کند. .NET ، جریان بنویسید. تشخیص جانشین ها ضروری است. بدین منظور

نکته: اگر کامپیوتر شما یک فونت برای پشتیبانی کاراکترهای یونیکد را داشته باشد، م یتواند آنها را نمایش دهید. در

یک فونت مربوط به یونیکد را نصب کنید. برنام ههای کنسولی ttfext.exe سیستم عامل ویندوز م یتوانید با استفاده از

نم یتوانند کاراکترهای یونیکد را چاپ کنند، چون خروجی کنسول همواره در یک سبک حروف نامتناسب نمایش داده

م یشود.

1 Surrogate

#C فصل بیستم دستکاری متن دز

335

-2-1-20 کار با کاراکترها

تعداد کمی عضو char نمایش داده می شود. ساختار Char یا کلاس char یک کاراکتر واحد به صورت یک ساختار .NET در

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

char انتساب یک مقدار به یک نوع داده ی

در char با یک مقدار حرفی است. با این وجود، چون یک مقدار ،char واضح ترین روش انتساب یک مقدار به یک متغیر

درون به صورت یک عدد نمایش داده م یشود، می توانید یک مقدار عددی نیز به آن انتساب دهید. اینها مثال هایی هستند.

string klm = "KLM";

byte b = 75;

char k;

// Different ways to assign 'K' to variable K

k = 'K';

k = klm[0]; // Assign "K" from first value in klm

k = (char) 75; // Cast decimal

k = (char) b; // cast byte

k = Convert.ToChar(75); // Converts value to a char

به یک مقدار عددی Char تبدیل یک مقدار

زمانی که یک کاراکتر به یک عدد تبدیل می شود، نتیجه ی آن مقدار یونیکد کاراکتر است. قال ب بندی، مؤثرترین روش انجام

یک رقم می باشد و شما می خواهید char می تواند به کار برده شود. در حالت خاصی که Convert این کار است، اگرچه متد

استفاده کنید. GetNumericValve یک مقدار وابسته به زبان شناسی 1 انتساب دهید، می توانید از متد ایستایی

// '7' has Unicode value of 55

char k = '7';

int n = (int) k; // n = 55

n = (int) char.GetNumericValue(k); // n = 7

-3-1-20 کاراکترها و محلی کردن

توانایی تشخیص اتوماتیک و اعمال قوانین فرهنگ خاص یک زبان یا یک کشور به یک ،.NET یکی از مهمترین ویژگیهای

برنامه ی کاربردی است. این پروسه به محلی کردن معروف است، که نحوه ی فرمت دهی اعداد، تاریخ، نمایش سمب لهای واحد

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

CLR . 2004 نشان می دهد /9/ 9 نشان می دهد و در تگزاس به صورت 5 May یک کاربر در پاریس تاریخ را به صورت 2004 و

به طور اتوماتیک فرهنگ کامپیوتر محلی را تشخیص داده و تنظی مها را انجام می دهد.

جهت معین کردن زبان/ کشور CultureInfo بیش از یکصد نام و مشخصه فرهنگ فراهم می کند که کلاس .NET چارچوب

استفاده می شود تا در عملیات حساس به فرهنگ در یک برنامه بکار برده شود. اگرچه در زمان کار با رشته ها، محلی کردن اثر

یک روش مفید برای نمایش این مفهوم است. Char.ToUpper بیشتری دارد، در این مثال متد

// Include the System.Globalization namespace

// Using CultureInfo – Azerbaijan

char i = 'i';

// Second parameter is false to use default culture settings

// associated with selected culture

CultureInfo myCI = new CultureInfo("az", false );

i = Char.ToUpper(i,myCI);

1 Linguistic

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

336

برای تعیین فزهنگ می گیرد، که در اجرای متد استفاده CultureInfo یک شی ToUpper از متد OverLoad یک

را می بیند، آن CultureInfo پارامتر CLR اختصار زبان آذری کشور آذربایجان است. زمانی که az ، می شود. در این مثال

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

فرهنگ پیش فرض سیستم را در نظر می گیرد. CLR

اطلاعات فرهنگ پیش فرض را از تنظیمات کشور و فرهنگ سیستم بدست می آورد. .NET در سیستم عامل ویندوز، چارچوب

انتساب می دهد. می توانید این گزینه را Thread.CurrentThread.CurrentCulture آن این مقادیر را به خصوصیت

انتخاب کنید. Control Panel در Regional Options با استفاده از

چرا آذربایجان یک کشور کوچک بالای دریای خزر را برای ارائه محلی کردن انتخاب کردیم؟ بین همه کشورهای دنیا که

0049 ) نشان نمی دهند. بلکه با یک I(U+ را با i مجموعه کاراکتر لاتین را به کار می برند، فقط آذربایجان و ترکیه حرف بزرگ

این عمل را درست انجام ()ToUpper 0130 ) نشان می دهند. برای اطمینان از اینکه متد U+) که در بالای آن یک نقطه است I

ایجاد کرده و به متد مورد نظر رد کنیم. این (az) با نام و فرهنگ آذری CultureInfo می دهد، ما باید یک نمونه از کلاس

عمل کاراکتر یونیکد را درست نتیجه م یدهد و 8,3 میلیون آذربایجانی را راضی نگه می دارد.

-4-1-20 کاراکترها و دسته های یونیکد آنها

را UnicodeCategory یک نوع شمارشی .NET . استاندارد یونیکد، کاراکترها را به یکی از 30 دسته تقسیم بندی می کند

دسته ی کاراکتر را بر م یگرداند. در اینجا ()Char.GetUnicodeCategory برای نمایش این دست هها فراهم می کند و متد

یک مثال آمده است:

Char k = 'K';

int iCat = (int) char.GetUnicodeCategory(k); // 0

Console.WriteLine(char.GetUnicodeCategory(k)); // UppercaseLetter

char cr = (Char)13;

iCat = (int) char.GetUnicodeCategory(cr); // 14

Console.WriteLine(char.GetUnicodeCategory(cr)); // Control

Control معین می کند و کاراکتر برگشت را به صورت یک UpperCaseLetter را به طور صحیح به عنوان یک K این متد

یک مجموعه از متدهای ایستا را به صورت یک میانبر برای تعیین دسته ی یونیکد کاراکتر دارد. آنها بر char . بر می گرداند

1 این متدها را لیست - بر می گردانند. جدول 20 true یا false یک مقدار GetUnicodeCategory اساس فراخوانی

می کند.

5- جدول 1

متد دسته یونیکد توصیف

IsControl

یا F007U+ 4 کد این کاراکترها

یا F001U+ 000 تا U+ در محدود هی

است. U+009F تا U+0080

IsDigit 8 در محدود هی 0 تا 9

IsLetter 0،1،2،4 حروف

IsLetterorDigit 0،1،8 اجتماع حروف و ارقام

IsLower 1 حروف کوچک

#C فصل بیستم دستکاری متن دز

337

IsUpper 0 حروف بزرگ

IsPunctuation

,22 ,21 ,20 ,19 ,18

24 ,23

سمبل تأکید مثال

DashPunctuation(19)

OpenPunctuation(20),

OtherPunctuation(24).

IsSeparator 11،12،13 جدا کننده فاصله، جداکننده خط،

جدا کننده پاراگراف

IsSurrogate 16 مقدار آن یک جانشین بالا یا پایین است.

IsSymbol 25،26،28 سمبل

IsWhiteSpace 11 فضاهای خالی م ی توانند هر کدام یک از

20X این کاراکترها باشند. 0

کاراکتر برگشت) ) D0X (فضای خالی) 0

خط جدید) ) A0X افقی) 0 (tab 09X0

عمودی) B (tab0X فرم جدید) 0 ) C0X0

دارند که یکی از آنها یک کاراکتر واحد را به OverLoad کاربرد این متدها سر راست است. نکته ی جالب اینکه، آنها دو تا

عنوان پارامتر می گیرد و دیگری دو پارامتر یکی رشته و دیگری اندیس کاراکتر را می گیرد.

Console.WriteLine(Char.IsSymbol('+')); // true

Console.WriteLine(Char.IsPunctuation('+')): // false

string str = "black magic";

Console.WriteLine(Char.IsWhiteSpace(str, 5)); // true

char p = '.';

Console.WriteLine(Char.IsPunctuation(p)); // true

Int iCat = (int) char.GetUnicodeCategory(p); // 24

Char p = '(';

Console.WriteLine(Char.IsPunctuation(p)); // true

int iCat = (int) char.GetUnicodeCategory(p); // 20

-2-20 کلاس رشته

کلاس رشته قبلاً استفاده شده است. این فصل نگاهی دقیق روی ایجاد، مقایسه و فرم تدهی رشته ها دارد.

-1-2-20 ایجاد رشت هها

و انتساب یک مقدار به آن ایجاد می شود. مقدار موردنظر ممکن است یک string یک رشته با اعلان یک متغیر از نوع

رشته ی حرفی یا رشت هی ایجاد شده با عمل الحاق باشد. این یک پروسه ی سرسری است و اغلب برنام هنویسان در زمان بهبود

یک فهم از نحوه ی اداره کردن رشت ههای حرفی م یتواند در بهبود کارایی آن به .NET کارایی کد به آن توجهی ندارند. در

توسعه دهنده کمک کند.

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

338

-2-2-20 داخل کردن 1 رشته ها

قبلاً در مورد نحوة ذخیر هی انواع داد ه مقداری و ارجاعی در حافظه بحث شده است. بیاد دارید که انواع داد هی مقداری روی

CLR مدیریت شده جای می گیرند. همچنین Heap ذخیره می شوند. در حالیکه انواع داده ی ارجاعی روی یک Stack یک

یک ناحیه ی سومی در حافظه به نام استخر داخلی 2 کنار می گذارد که در طول کامپایل، همه رشته های حرفی در آن ذخیره

می شوند. با استفاده از این استخر تکثیر کپی مقادیر رشت های ذخیره شده حذف می گردد. کد زیر را بررسی کنید.

string poem1 = "Kubla Khan";

string poem2 = "Kubla Khan";

string poem3 = String.Copy(poem2); // Create new string object

string poem4 = "Christabel";

2 یک دید ساده از نحو هی ذخیره رشته ها و مقادیر آنها در حافظه را نشان می دهد. - شکل 20

2- شکل 20

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

کد قبلی را کامپایل می کند، ،JIT مدیریت شده ارجاع می کند. زمانی که کامپایلر heap شی رشت هی انتساب یافته در روی

مدیریت شده ایجاد heap را در استخر قرار می دهد و یک ارجاع به شی رشته در روی ”Kubla Khan“ آن اولین نمونه از

می بیند این رشته در حافظه وجود CLR ، 2) روبرو می شود Kubla Khan” (poem“ می کند. زمانی که آن با ارجاع دوم به

1) ارجاع می دهد. این پروسه به داخل poem) 2 را به همان شی poem ، دارد، بدین دلیل به جای ایجاد یک رشت هی جدید

3 ایجاد می کند. در روی Poem یک رشته ی جدید به نام String.Copy کردن رشته ها معروف است. در ادامه ی مثال، متد

4 به استخر اضافه poem مدیریت شده یک شی برای آن ایجاد می کند. سرانجام، رشته ی حرفی انتساب داده شده به heap

می شود.

برای بررسی اثرات عملی داخل کردن رشته، اجازه دهید مثال قبلی را توسعه دهیم. کدی اضافه می کنیم که عملگر تساوی

را برای مقایسه آدرس آنها اضافه Object.ReferenceEqual (==) را برای مقایسه مقادیر رشته ای به کار می برد و متد

می کند.

Console.WriteLine(poem1 == poem2); // true

Console.WriteLine(poem1 == poem3); // true

Console.WriteLine(ReferenceEquals(poem1, poem3)); // false

Console.WriteLine(ReferenceEquals(poem1,

"Kubla Khan")); // true

1 Interning

2 Intern Pool

#C فصل بیستم دستکاری متن دز

339

بر می گردانند. دستور سوم موقعیت حافظ هی متغیرهای true دو دستور اول مقدار متغیرها را مقایسه می کنند و یک مقدار

برگردانده می شود. false ارجاع دارند مقدار heap 2 را مقایسه می کند. چون آنها به اشیاء مختلفی در روی poem 3 و poem

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

برای اضافه کردن یک رشته ی پویا به استخر حرفی String.Intern رشته، روی کارایی اثر منفی دارد. با این وجود، متد

استفاده می شود.

string khan = " Khan";

string poem5 = "Kubla" + khan;

Console.WriteLine(ReferenceEquals(poem5, poem1)); // false

// Place the contents of poem5 in the intern pool—if not there

poem5 = String.Intern(poem5);

Console.WriteLine(ReferenceEquals(poem5, poem1)); // true

را در استخر داخلی جستجو م یکند. چون آن رشته در استخر (”(“Kubla Khan 5poem مقدار String.Intern متد

5 انتساب می دهد. چون poem وجود دارد، نیازی نیست اضافه گردد. متد یک ارجاع به ش ی موجود بر می گرداند و آن را به

است. توجه داشته باشید که true 1 به شی یکسانی اشاره می کنند، عمل مقایسه در دستور آخری مقدار poem 5 و poem

بعدی جاروب می شود. GC 5 آزاد می شود و در حین poem شی ایجاد شده برای

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

را بکار برید. String.Intern

-3-2-20 مروری بر عملیات رشته ها

دارند. این OverLoad تعداد زیادی متد ایستا و نمونه فراهم می کند، که بیشتر آنها چندین شکل System.String کلاس

متدها بر اساس عملکرد اصلی آنها به 4 دسته اصلی گرو هبندی می شوند.

روش های مختلفی برای String.CompareOrdinal و String.Equals ،String.Compare مقایسه رشته: متدهای

مقایسه ی مقادیر رشته ای پیشنهاد می کنند. انتخاب یک روش به نوع مقایسه (ترتیبی یا حرفی) وابسته است و اینکه آیا

حالت و فرهنگ عمل را در نظر بگیرد یا نه.

اندیس گذاری و جستجو: یک رشته آرایه ای از کاراکترهای یونیکد است که با ط یکردن سراسر آرایه یا با استفاده از متدهای

اندیس خاص م یتوان مقادیر رشته ای را تعیین محل کرد.

تبدیل رشته ها: این دسته از عملیات شامل درج، پیمایش، حذف، جایگذاری، حذف فضاهای خالی و جدا کردن رشته های

کاراکتری است.

بیشتر متدهای رشته به فرهنگ وابسته هستند. هر جا که لازم باشد، نحوه تأثیر فرهنگ روی رفتار یک متد را نشان خواهیم

داد.

-3-20 مقایسه ی رشت هها

ساده ترین راه تعیین مساوی بودن دو رشته این است که ببینیم آیا آنها به آدرس حافظه یکسانی اشاره می کنند. ما این کار را

انجام می دهیم. اگر دو رشته آدرس یکسانی را به اشتراک نگذارند، مقایسه کاراکتر ReferenceEquals با استفاده از متد

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

کرد.

را فراهم کرد که هر دو نوع عمل مقایسه را به طور اتوماتیک انجام Equals برای بهینه کردن پروسه ی مقایسه، متد .NET

می دهد. می توانیم عمل آن را در شبه کد زیر شرح دهیم.

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

340

If string1 and string2 reference the same memory location

Then strings must be equal

Else

Compare strings character by character to determine equality

را نشان می دهد. Equals این قطعه کد شک لهای ایستا و ارجاع متد

string poem1 = "Kubla Khan";

string poem2 = "Kubla Khan";

string poem3 = String.Copy(poem2);

string poem4 = "kubla khan";

//

Console.WriteLine(String.Equals(poem1,poem2)); // true

Console.WriteLine(poem1.Equals(poem3)); // true

Console.WriteLine(poem1 == poem3); // equivalent to Equals

Console.WriteLine(poem1 == poem4); // false – case differs

را فراخوانی می کند.) روش مطلوب تر بیان عمل مقایسه است. اگرچه متد Equals توجه کنید که عملگر==، (که متد

ی برای گرفتن فرهنگ حساب کاربری و حساسیت OverLoad بیشتر نیازهای مقایسه را برآورده می سازد، آن هیچ Equals

این محدودیت ها را رفع می کند. String کلاس Compare حروف را ندارد. متد

String.Compare -1-3-20 کاربرد

یک متد انعطاف پذیر در عمل مقایسه است که می تواند با در نظر گرفتن فرهنگ و حالت حروف بکار String.Compare

های زیادی برای گرفتن پارامترهای فرهنگ و حالت حروف دارد. OverLoad برده شود. آن

گرامر:

int Compare (string str1, string str2)

Compare (string str1, string str2, bool IgnoreCase)

Compare (string str1, string str2, bool IgnoreCase,

CultureInfo ci)

Compare (string str1, int index1, string str2, int index2,

int len)

پارامترها

رشته های مورد نظر جهت عمل مقایسه. : Str2, Str1

است. false باشد. به طور پی شفرض true برای در نظر نگرفتن حساسیت حروف باید :IgnoreCase

Str و 2 Str محل شروع در 1 :index1, index2

که فرهنگ مورد استفاده را نشان می دهد. CultureInfo یک شی :C2

یک مقدار صحیح بر می گرداند که نتیجه ی مقایسه را نشان می دهد. اگر دو رشته مساوی باشند، یک مقدار ()Compare متد

صفر برگردانده می شود. اگر رشته ی اول کوچکتر از رشته ی دوم باشد، یک مقدار منفی برگردانده می شود. اگر رشته اول

بزرگتر از رشته ی دوم باشد، یک مقدار مثبت برگردانده م یشود.

را برای در نظر گرفتن فرهنگ و حساسیت حروف نشان می دهد. Compare قطعه کد زیر نحو هی استفاده از دستور

int result;

string stringUpper = "AUTUMN";

string stringLower = "autumn";

// (1) Lexical comparison: "A" is greater than "a"

result = string.Compare(stringUpper,stringLower); // 1

// (2) IgnoreCase set to false

result = string.Compare(stringUpper,stringLower,false); // 1

// (3)Perform case-insensitive comparison

result = string.Compare(stringUpper,stringLower,true); // 0

#C فصل بیستم دستکاری متن دز

341

لیستی از قوانین مقایسه برای هر .NET . شاید اثر نهایی اطلاعات فرهنگ روی عمل مقایسه مهمتر از حالت حروف باشد

فرهنگ اختصاص داده شده را بررسی می کند و قوانین آن را اعمال CLR ، اجرا م یشود Compare فرهنگ دارد. زمانی که متد

یا یک فرهنگ ژاپنی به طور مختلف مقایسه US می کند. نتیجه اینکه، ممکن است دو رشته روی یک کامپیوتر با فرهنگ

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

برنامه مطمئن شوند. برای مثال، بسیار مهم است که یک عمل مرت بسازی در هر جایی که اجرا م یشود، درست و دقیق اجرا

گردد.

اطلاعات فرهنگ را بر اساس مقدار خصوصیت Compare به طور پیش فرض متد

بکار می برد. برای باطل کردن مقدار پیش فرض، یک ش ی Thread.CurrentThread.CurrentCulture

نشان Germany به عنوان پارامتر متد تهیه کنید. دستور زیر نحوه ی ایجاد یک شی برای ارائه زبان و کشور CultureInfo

می دهد.

CultureInfo ci = new CultureInfo("de-DE"); // German culture

دو خصوصیت دارد که به عنوان پارامتر CultureInfo برای تعیین صریح یک فرهنگ پی شفرض یا هیچ فرهنگی، کلاس

InvariantCulture برای استفاده کردن فرهنگ ریسمان جاری استفاده م یشود و CurrentCulture : می تواند بگیرد

که از هر فرهنگی چشم پوشی می کند.

را نشان می دهد. ()Compare مثل زیر نحوه تأثیر فرهن گهای مختلف روی نتیج هی عمل

using System.Globalization; // Required for CultureInfo

// Perform case-sensitive comparison for Czech culture

string s1 = "circle";

string s2 = "chair";

result = string.Compare(s1, s2,

true, CultureInfo.CurrentCulture)); // 1

result = string.Compare(s1, s2,

true, CultureInfo.InvariantCulture)); // 1

// Use the Czech culture

result = string.Compare(s1, s2,

true, new CultureInfo("cs-CZ")); // -1

هیچ فرهنگی و فرهنگ چکوسلواکی ،US با استفاده از سه حالت فرهنگ ”Chair” , “Circle“ دو مقدار رشته ای

مقایسه می شوند. دو مقایس هی اول مقدار مثبت بر م یگردانند، در حالی که در فرهنگ چکوسلواکی مقدار منفی بر می گرداند.

ظاهر می گردد. C به صورت یک کاراکتر تکی در نظر گرفته می شود که بعد از کاراکتر ”Ch“ چون در قوانین زبان چکوسلواکی

CultureInfo در صورتی که می خواهید یک برنامه ای بنویسید که اطلاعات فرهنگ کاربر جاری را بکار برد، یک پارامتر

صریح بکار برید تا در عملیات رشت های مشکلی پیش نیاید.

String.CompareOrdinal -2-3-20 کاربرد

را بکار برید. آن String.CompareOrdinal . اگر می خواهید یک مقایسه براساس مقدار ترتیبی کاراکترها انجام دهید

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

صورتی که رشته ی اول بزرگتر از رشته دوم باشد، مقدار کوچکتر از صفر بر می گرداند، در غیر اینصورت مقدار بزرگتر از صفر

را نشان م یدهد. CompareOrdinal و Compare بر می گرداند. کد زیر تفاوت مابین

string stringUpper = "AUTUMN";

string stringLower = "autumn";

//

result = string.Compare(stringUpper,stringLower,

false, CultureInfo.InvariantCulture); // 1

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

342

result = string.CompareOrdinal(stringUpper,stringLower); // -32

یک مقایسه ی حرفی انجام می دهد که رشته حروف بزرگ از رشته حروف کوچک، بزرگتر است. Compare متد

کمتر است، رشته اول کوچکتر از ()a0061U+ 0041 ) از A(U+ مقادیر یونیکد را بررسی می کند. چون CompareOrdinal

دومی است.

-4-20 جستجو، تغییر و کدگذاری محتوای یک رشته

را شرح می دهد که نسبت به کارهای آشنا همچون محل یابی یک ریز رشته در رشته، تغییر String این بخش متدهایی از

حالت حروف یک رشته و جایگذاری و حذف زیر رشته و غیره متفاوت عمل می کنند.

-1-4-20 جستجوی محتویات یک رشته

موقعیت یک n می تواند جستجو شود، که ([String[n) رشته یک آرای های از کاراکترها است و با استفاده از گرامر آرایه

متدهای String کاراکتر در رشته است. برای محل یابی یک زیررشته ی یک یا چند کاراکتری در یک رشته، کلاس

2 این متدها را خلاصه می کند. - را پیشنهاد می کند. جدول 20 IndexOfAny و IndexOf

2- جدول 20

عضو توصیف

از رشته را فهرست م یکند. n یک کاراکتر 16 بیتی قرار گرفته در موقعیت [n]

;Int ndx=0

(While (ndx<poem.length

}

;([Console. Write (Poem[ndx

;1Ndx+=

{

IndexOf /LastIndexOf

String, [int stat, )

([[int count

تعداد کاراکترهای Cont

مورد بررسی است.

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

تطابقی رخ ندهد، 1- بر می گرداند.

”String Poem=”kubla khan

Int n=Poem.Index of (“la”);//3

0n=Poem.Index of (“h”);//

6);//4n=Poem Index of (‘k’,

IndexOfAny/LastIndex

اندیس اولین/ آخرین کاراکتر را در یک آرایه از کاراکترهای یونیکد بر OfAny

می گرداند.

;”String Poem=”kubla khan

[Char[ ] Vowels = new char [5

;{’’, ‘u0’, ‘2a’, ‘e’, ‘‘}

N=Poem. Index of on (Vowels); //1

N=Poem. Last Index of Any (Vowels);//8

N=Poem. Index of Any (Vowels, 2);//4

#C فصل بیستم دستکاری متن دز

343

-2-4-20 جستجوی رشت هی جانشین دار

همه این تکنیک ها فرض می کنند هر رشته یک دنباله از کاراکترهای 16 بیتی را در بر دارد. فرض کنید برنامه کاربردی شما با

مجموعه کاراکتر 32 بیتی خاور دور کار می کند. اینها در حافظه به صورت یک زوج جانشین شامل یک مقدار 16 بیتی بالا و

یک مشکل پیش می آید که فقط نصف یک زوج جانشین را بر [Poem[ndx پایین نمایش داده می شوند. برای عبارتی همچون

می گرداند.

با همه کاراکترها به صورت عناصر متنی .NET در String در برنامه هایی که باید از این جانشی نها استفاده کنند، کلاس

برخورد می کند و می تواند به طور اتوماتیک یک کاراکتر 16 بیتی را از یک کاراکتر جانشین تشخیص دهد. مهمترین عضو آن

است که یک نوع شمارشی بر می گرداند. این نوع شمارشی م یتواند برای طی کردن GetTextElementEnumerator متد

سراسر عناصر متنی در یک رشته استفاده شود.

TextElementEnumerator tEnum =

StringInfo.GetTextElementEnumerator(poem) ;

while (tEnum.MoveNext()) // Step through the string

{

Console.WriteLine(tEnum.Current); // Print current char

}

پیاده سازی می شوند. Current و ()MoveNext به خاطر دارید که در انواع داده شمارشی، متدهای

-3-4-20 تبدیل رشته ها

را برای تغییر دادن یک رشته خلاصه می کند. چون رشته ی اصلی غیر قابل String 3 مهمترین متدهای کلاس - جدول 20

تغییر است، این متدها رشت ههای جدیدی ایجاد می کنند که حافظه خاص خود را دارند.

3- جدول 20

متد توصیف

یک رشته را در محل مشخص شده درج می کند. (Insert (int, string

string mariner = "and he stoppeth three";

string verse = mariner.Insert(

mariner.IndexOf(" three")," one of");

// verse --> "and he stoppeth one of three"

در سمت چپ یا راست یک رشته کاراکتر خاصی را تکرار می کند تا طول PadLeft/PadRight

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

اضافه می گردد.

string rem = "and so on";

rem =rem.PadRight(rem.Length+3,'.);

// rem --> "and so on..."

حذف می کند. p کاراکتر را با شروع از محل n تعداد (Remove(p,n

string verse = "It is an Ancient Mariner";

string newverse = (verse.Remove(0,9));

// newverse --> "Ancient Mariner"

کاراکتر یا رشته B و A . جایگزین م یکند B را با A همه ی زیررشته های (Replace(A,B

هستند.

String astring = “nap ace sap. Path”;

اسلام احمد زاده - 09177112161 - C# برنامهنویسی

344

String istring=astring.Replace (‘a’,’1’);

//istring--> “nip ice sip pith”

لیست جدا کننده ها وجود دارد که یک رشته را به Char در آرایه ی ([]Split(Char

چندین زیررشته تقسیم م یکنند و نتیجه در یک آرای هی رشته ای بر

گردانده می شود.

string words = "red,blue orange ";

string [] split = words.Split(new Char []

{' ', ','});

Console.WriteLine(split[2]); // orange

()Toupper

(Toupper(CultureInfo

() Tolower

(Tolower(CultureInfo

یک کپی از رشته با حروف بزرگ یا کوچک بر می گردانند.

String Poem2= “kubla khan”;

Poem2=Poem2. Toupper (Culture Info. Invarian+Culture);

([]Trim (params Char

()Trim

[]Char فضاهای خالی ابتدا و انتهای رشته را حذف م یکند. اگر آرای هی

خالی نباشد، همه کاراکترهای این آرایه در ابتدا و انتهای رشته حذف

می شوند.

String name=” Samuel Coleridge”;

Nam=name.Trim( );

([]TrimEnd (params Char

TrimStart(params Char

([]

را از ابتدا یا انتهای رشته Char همه کاراکترهای مشخص شده آرای هی

باشد، فضاهای خالی حذف خواهند null حذف می کنند. اگر مقدار آرایه

شد.

String name=”Samuel Coleridge”;

Trino Name=nam. Trimstart(null);

Shortname=name. Trim END(‘e’,’g’,’I’);

//Short Name → ”Samuel Colerid”;

(SubString (n

(Substring (n,l

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

خواهد بود. L مشخص شده باشد طول این زیر رشته L اگر

String title = “kubla khan”;

Console. Write line (title. Substring (2،3)); //bla

()ToCharArray

(ToCharArray(n,l

کاراکترهای یک رشته را استخراج کرده و در یک آرایه از کاراکترهای

یونیکد قرار می دهد.

String my Vowels= “aeiou”;

Char{ ] Vowel Arr;

Vowel Arr=myVowels. Tochar Array( );

Console write line (Vowel Arr [1]);

بیشتر این متدها شبیه زبانهای دیگر هستند و همانند انتظار شما رفتار می کنند. مورد جالب این است که بیشتر این متدها

وجود دارد. Insert و Remove, Replace نیستند. فقط StringBuilder در کلاس

#C فصل بیستم دستکاری متن دز

345

-4-4-20 کدگذاری رشته

زمانی که لازم باشد رشته ها و بایت ها برای عملیاتی همچون نوشتن در یک فایل یا جاری شدن روی شبکه تبدیل گردند، از

کدگذاری رشته استفاده می کنند. کدگذاری و کدگشایی کاراکترها دو فاید هی اصلی پیشنهاد م یکنند: کارایی و قابلیت

ارتباط بین پروسه ها. بیشتر کاراکترهای متون انگلیسی می توانند با 8 بیت نمایش داده شوند. با استفاده از کدگذاری می توان

بایت اضافی را در انتقال و ذخیره سازی حذف کرد. انعطاف پذیری و رمزگذاری، ارتباط یک برنامه با داده های موروثی 1 یا

داده های ثالث 2 با فرم تهای مختلف را ممکن می سازد.

شکل های زیادی از کدگذاری و کدگشایی کاراکترها را پشتیبانی می کند. معمول ترین آنها به صورت زیر .NET چارچوب

هستند.

UTF-8

هر کاراکتر بر اساس مقدار اصلی آن با یک تا 4 بایت کدگذاری می شود. کاراکترهای سازگار با اسکی در یک بایت ذخیره

در دو بایت ذخیره م یشوند و کاراکترهایی که یک مقدار بزرگتر یا مساوی FF07X 0800 تا 0 X می شوند. کاراکترهای مابین 0

0800 دارند به سه بایت تبدیل می شوند و جانشین ها به صورت 4 بایتی نوشته می شوند. زمانی که کدگذاری مد نظر نباشد، x0

8 را بکار می برند. UTF به طور پی شفرض .NET کلاس های

UTF16

هر کاراکتر با 2 بایت کدگذاری می شوند(به استثناء جانشی نها). این کدگذاری را کدگذاری یونیکد نیز گویند.

ASCII

هستند از f7OX 00 تا OX هر کاراکتر به صورت یک کاراکتر 8 بیتی اسکی کدگذاری می شود. زمانی که همه کاراکترها مابین

این کد استفاده کنید.

انجام می شوند. این کلاس انتزاعی چندین Encoding با کلاس System.Text کدگذاری و کدگشایی در فضای نامی

8UTF ،ASCII خصوصیت ایستا دارد که برای پیاده سازی تکنیک کدگذاری خاص، یک ش ی بر می گردانند. این خصوصیات

16 است. UTF هستند. آخری برای کدگذاری Unicode و

های مختلف جهت تبدیل کاراکترها و بایت ها پیشنهاد می کند. در این مثال دو overload یک شی کدگذاری چندین متد با

عکس این عمل را GetString یک رشته متنی را به بای تها تبدیل می کند و GetBytes : متد بسیار مفید ارائه می گردد

انجام م یدهد.

string text= "In Xanadu did Kubla Khan";

Encoding UTF8Encoder = Encoding.UTF8;

byte[] textChars = UTF8Encoder.GetBytes(text);

Console.WriteLine(textChars.Length); // 24

// Store using UTF-16

textChars = Encoding.Unicode.GetBytes(text);

Console.WriteLine(textChars.Length); // 48

// Treat characters as two bytes

string decodedText = Encoding.Unicode.GetString(textChars);

Console.WriteLine(decodedText); // "In Xanadu did ... "

1 Legacy

2 Third Party

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

346

8 می تواند به صورت زیر ایجاد UTF- همچنین م یتوانید اشیاء کدگذاری را به طور مستقیم تعریف کنید. در این مثال، ش ی

شود.

UTF8Encoding UTF8Encoder = new UTF8Encoding();

پارامترهایی را برای کنترل بیشتر روی پروسه ی کدگذاری تعریف ،ASCIIEncoding سازنده ی این کلا سها به استثناء

می کنند. به عنوان مثال، مشخص می کنند در صورت مواجه شدن با یک کاراکتر نامعتبر، یک استثناء رها شود.

StringBuilder -5-20 کلاس

عیب اصلی رشت هها این است که در هر زمان با تغییر محتویات یک متغیر رشت های، باید به آن حافظه تخصیص یابد. فرض

کنید یک حلقه ایجاد کردیم که 100 بار تکرار می شود و یک کاراکتر را به یک رشته الحاق می کند. ما در حافظه 100 تا رشته

داریم که هر کدام با رشته ی قبلی فقط در یک کاراکتر اختلاف دارند.

با تخصیص یک ناحی هی کاری (بافر) که متدهای آن می توانند روی رشته اعمال شوند، این مشکل StringBuilder کلاس

را حل می نماید. این متدها راه هایی را برای الحاق کردن، درج کردن، پاک کردن، حذف کردن و جایگزین کردن کاراکترها

برای تبدیل بافر به یک رشته در متغیر رشت های استفاده می شود. ()ToString دارند. بعد از اتمام عملیات، متد

را برای ایجاد یک لیست تفکیک شده با کاما بیان می کند. StringBuilder 1 بعضی از متدهای - قطعه کد 20

1- قطعه کد 20

using System;

using System.Text;

public class MyApp

static void Main()

{

// Create comma delimited string with quotes around names

string namesF = "Jan Donna Kim ";

string namesM = "Rob James";

StringBuilder sbCSV = new StringBuilder();

sbCSV.Append(namesF).Append(namesM);

sbCSV.Replace(" ","','");

// Insert quote at beginning and end of string

sbCSV.Insert(0,"'").Append("'");

string csv = sbCSV.ToString();

// csv = 'Jan','Donna','Kim','Rob','James'

}

}

همه عملیات در یک بافر واحد رخ م یدهند و تا انتساب نهایی هیچ عمل تخصیص حافظه نیاز نیست. نگاه رسمی به این

کلاس و اعضای آن می افکنیم.

StringBuilder -1-5-20 مروری بر کلاس

یک مقدار رشته ای اولیه را همانند مقادیر صحیح می پذیرند تا مقدار فضای اولیه و StringBuilder سازنده های کلاس

حداکثر فضای تخصیص یافته به بافر را معین کنند.

// Stringbuilder(initial value)

StringBuilder sb1 = new StringBuilder("abc");

// StringBuilder(initial value, initial capacity)

StringBuilder sb2 = new StringBuilder("abc", 16);

// StringBuiler(Initial Capacity, maximum capacity)

StringBuilder sb3 = new StringBuilder(32,128);

امکان استفاده از آن به عنوان یک بافر برای انجام عملیات رشته ای است. در این مثال نحوه ی کار StringBuilder ایده ی

را می بینید. Remove و Replace ،Insert ،Append متدهای

#C فصل بیستم دستکاری متن دز

347

int i = 4;

char[] ch = {'w','h','i','t','e'};

string myColor = " orange";

StringBuilder sb = new StringBuilder("red blue green");

sb.Insert(0, ch); // whitered blue green

sb.Insert(5," "); // white red blue green

sb.Insert(0,i); // 4white red blue green

sb.Remove(1IR); // 4 red blue green

sb.Append(myColor); // 4 red blue green orange

sb.Replace("blue","violet"); // 4 red violet green orange

string colors = sb.ToString();

و الحاق رشته StringBuilder -2-5-20 مقایسه ی

را در برابر عملگر الحاق آزمایش م یکند. بخش اول این برنامه عملگر + را برای StringBuilder 2 بهره وری - قطعه کد 20

به یک رشته در حلق های با 50000 تکرار بکار می برد. بخش دوم نیز همان کار را انجام م یدهد. اما متد ’a‘ الحاق حرف

زمان شروع و پایان را در واحد میلی ثانیه ، Environment.TickCount . را بکار می برد StringBuilder.Append

تهیه می کند.

2- قطعه کد 20

using System.Text;

public class MyApp

static void Main()

{

Console.WriteLine("String routine");

string a = "a";

string str = string.Empty;

int istart, istop;

istart = Environment.TickCount;

Console.WriteLine("Start: "+istart);

// Use regular C# concatenation operator

for(int i=0; i<50000; i++)

{

str += a;

}

istop = Environment.TickCount;

Console.WriteLine("Stop: "+istop);

Console.WriteLine("Difference: " + (istop-istart));

// Perform concatenation with StringBuilder

Console.WriteLine("StringBuilder routine");

StringBuilder builder = new StringBuilder();

istart = Environment.TickCount;

Console.WriteLine("Start: "+istart);

for(int i=0; i<50000; i++)

{

builder.Append(a);

}

istop = Environment.TickCount;

str = builder.ToString();

Console.WriteLine("Stop: "+Environment.TickCount);

Console.WriteLine("Difference: "+ (istop-istart));

}

}

اجرای این برنامه خروجی زیر را نتیجه م یدهد.

String routine

Start: 1422091687

Stop: 1422100046

Difference: 9359

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

348

StringBuilder routine

Start: 1QOONMMMQS

Stop: 1422100062

Difference: 16

StringBuilder . طول می کشد StringBuilder الحاق استاندارد مدت زمان 9,359 میلی ثانیه در برابر 16 میلی ثانیه

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

-6-20 فرمت دهی مقادیر عددی، تاریخ و زمان

وسیله ی اصلی فرمت دهی تاریخ و داده های عددی جهت نمایش است. آن یک رشته مرکب از متن و String.Format متد

عناصر فرمت تعبیه شده در آن را به همراه یک یا چند آرگومان داد های می پذیرد. هر عضو فرمت به یک آرگومان داد های

رشته ی خروجی را با تبدیل هر مقدار داد های به یک رشته، CLR . ارجاع می کند و نحو هی فرمت دهی آن را مشخص م یکند

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

ساده است.

String s= String.Format("The square root of {0} is {1}.",64,8);

// output: The square root of 64 is 8.

دارد. اما این معمو لترین است و دو ویژگی مشترک همه را ارائه م یکند: یک رشت ه ی فرمت و Overload این متد چندین

همان پارامترها را می گیرد و می تواند به Console.WriteLine یک لیست از آرگوما نهای داده ای. توجه کنید که متد

در خروجی کنسول استفاده شود. String.Format جای متد

-1 ساختن یک عنصر فرمت -6-20

را به اجزاء پای های آن می شکند. جالب ترین آنها عنصر فرمت است که روش نمایش داده String.Format 3 مثال - شکل 20

را تعریف می کند.

3- شکل 20

همانطور که می توانید ببینید، هر عنصر فرمت یک اندیس و یک آرگومان اختیاری ترازبندی و رشت هی فرمت را شامل است.

همه ی آنها در بین کاراکترهای {} قرار می گیرند.

1. اندیس یک مقدار صحیح با پایه صفر است که آرگومان داد های مرتبط با آن را نشان می دهد. اندیس می تواند چند بار در

یک رشته تکرار شود.

2. ترازبندی اختیاری، یک عدد صحیح است که حداقل طول ناحی هی مربوط به مقدار فرم تدهی شده را مشخص می کند.

اگر مقدار ترازبندی مثبت باشد، مقدار آرگومان، راس تچین است. اگر مقدار آن منفی باشد، آن چ پچین است.

#C فصل بیستم دستکاری متن دز

349

3. رشته فرمت اختیاری، کدهای فرم تدهی اعمال شده به مقدار آرگومان را در بر دارد. اگر آن مشخص نشده باشد،

چندین کد فرمت استاندارد برای ایجاد رشت ههایی با .NET . مربوط به آرگومان استفاده می شود ToString خروجی متد

فرمت سفارشی فراهم کرده است.

-2 فرمت دهی مقادیر عددی -6-20

9 کاراکتر یا مشخص ههای فرمت برای فرمت دهی اعداد به پول رایج، علمی، هگزادسیمال و نمایش های دیگر در دسترس

هستند. برای مشخص کردن دقت می توانید به هر کاراکتر یک عدد الحاق کنید. معمولاً این عدد تعداد ارقام اعشار را مشخص

4 را تشخیص م یدهد. - مشخصه های فرمت استاندارد جدول 20 #C . می کند

4- جدول 20

علامت

فرمت

توصیف الگو خروجی

عدد به صورت یک مقدار پولی نمایش م یگردد. دقت، C یا c

تعداد ارقام اعشار را نشان م یدهد.

1،458,75 $ 1458,75},2C:0}

اعداد دهدهی. به اعداد صحیح اعمال می گردد. دقت- D یا d

تعداد کل فضای اشغالی را مشخص می کند. فضاهای

خالی با صفر پر م یشوند.

۴۵۵}, ۵D:٠}

۴۵۵}, -۵D:٠}

00455

00455-

علمی. عدد به نمایش علمی تبدیل م یشود. E یا e

دقت تعداد ارقام اعشار را مشخص م یکند. ddddE+nnm

{٠،١٠:E٢}, ٣٢٩٨٫٧٨

+3,30 {٠،١٠:E۴}, -۵۴٧٨٣٫۴ 003E

-

5.4783+E004

تبدیل dddd.ddd نقطه اعشار ثابت. عدد به فرمت F یا f

می شود. دقت، تعداد ارقام اعشار را مشخص می کند.

{٠،١٠:F٠}, ١۶٢٫۵٧

162 {٠،١٠:F٢}, ٨١۶٢٫۵٧

8162,57

کلی. عدد بر اساس دقت و نوع عدد به اعشار ثابت یا G یا g

نمایش علمی تبدیل م یگردد. در صورتی که توان

بزرگتر مساوی دقت یا کمتر از - 4 باشد، از نمایش

علمی استفاده می شود.

{٠،١٠:G}, .٠٠٠٠٠٩٩

{٠،١٠:G٢}, ۴۵۵٫٨٩

{٠،١٠:G٣}, ۴۵۵٫٨٩

{٠،١٠:G},٧٨٣٢٢٩٫٣۴

9.9E-06

4.6E+02

456

783229.34

عدد. عدد را به یک رشته تبدیل می کند که هر 1000 با N یا n

کاما جدا می شود. تعداد ارقام اعشار را دقت مشخص

می کند.

{٠،١٠:N}, ١٠۴۵٫٧٨

{٠،١٠:N١}, ۴۵٫٩٨

1,045.78

4RKV

درصد. عدد به صد تقسیم می شود و به صورت درصد P یا p

نمایش داده می شود. تعداد ارقام اعشار با دقت

مشخص می گردد.

{٠،١٠:P}, ٠٫٧٨

{٠،١٠:P٣}, ٠٫٧٨۶۵

78.00 %

78.650 %

گرد کردن. عدد را به یک رشته تبدیل می کند که همه R یا r

ارقام اعشار به درستی حفظ م یشوند. باید عدد از نوع

اعشاری شناور باشد.

1.62736 {٠،١٠:R}, ١٫۶٢٧٣۶

هگزا دسیمال. عدد را به نمایش هگزا تبدیل می کند. X یا x {٠،١٠:X}, ٢۵

{٠،١٠:X۴}, ٢۵

{٠،١٠:x۴}, ٣١

19

001V

001f

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

350

دقت عدد حداقل تعداد ارقام قابل نمایش را نشان

می دهد. فضاهای اضافی با صفر پر می شوند.

قابل استفاده هستند. Console.WriteLine و Console.Write الگوهای این جدول مستقیماً در دستور

Console.WriteLine("The Hex value of {0} is {0:X} ",31); //1F

بکار روند. ToString علامت های فرمت م یتوانند برای بهبود خروجی متد

decimal pct = .758M;

Console.Write("The percent is "+pct.ToString("P2")); // 75.80 %

کاراکترهای فرمت دهی خاصی را برای ایجاد فرمت های عددی سفارشی فراهم می کند. معمول ترین آنها عبارتند از: #( .NET

علامت عدد)، 0(صفر)، ,(کاما)، . (نقطه)، % (درصد) و ;(سمی کالن). کد زیر کاربرد آنها را نشان می دهد.

decimal dVal = 2145.88M; // decimal values require M suffix

string myFormat;

myFormat = dVal.ToString("#####"); // 2146

myFormat = dVal.ToString("#,###.00"); // 2,145.88

myFormat = String.Format("Value is {0:#,###.00;

(#,###.00)}",-4567);

// semicolon specifies alternate formats. (4,567.00)

myFormat = String.Format("Value is {0:$#,###.00}", 4567);

// $4,567.00

Console.WriteLine("{0:##.00%}",.18); // 18.00 %

همه این کاراکترها به استثناء ; خود توصیف هستند. آن فرمت را به دو گروه تقسیم می کند. گروه اول به مقادیر مثبت و گروه

دوم به مقادیر منفی اعمال می شوند. دو سمی کالن برای ایجاد سه گروه برای اعداد مثبت، منفی و مقادیر صفر استفاده

می شوند.

-3 فرمت دهی تاریخ و زمان -6-20

نیاز داریم. همانند اعداد، این ش ی نیز مجموعه علائم استاندارد فرمت خود را DateTime در فرم تدهی تاریخ به یک ش ی

5 خلاصه ی آنها آمده است. - دارد. در جدول 20

5- جدول 5

علامت

فرمت

توصیف مثال انگلیسی مثال آلمانی

19,1,2004 2004/19/ تاریخ کوتاه 1 d

Monday, January تاریخ بلند D

19, 2004

Montag, 19

Januar,2004

Monday, January ( زمان/تاریخ کامل (زمان کوتاه f

19, 2004 4:05 PM

Montag, 19

Januar, 2004

16:05

Monday, January ( زمان/ تاریخ کامل (زمان کامل F

19, 2004 4:05:20 PM

Montag, 19

Januar,2004

16:05:20

6:05 2004/1/19 PM 4:05 2004/19/ زمان/ تاریخ کلی (زمان کوتاه) 1 g

16:05:20 2004/1/19 PM 4:05:20 2004/19/ زمان/ تاریخ کلی (زمان بلند) 1 G

#C فصل بیستم دستکاری متن دز

351

Januar 19 January روز/ ماه 19 m,M

Januar, 2004 January, ماه/ سال 2004 y,Y

16:05 PM زمان کوتاه 4:05 t

16:05:20 PM زمان بلند 4:05:20 T

8601 مطابقت Iso با زمان/ تاریخ جهانی S

می کند. زمان محلی را بکار می برد.

19 -01 -2004 16:05:20T 9 -01 -2004

16:05:20T

19 -01 -2004 Z16:05:20 19 -01 - زمان - تاریخ جهانی 2004 u

Z16:05:20

زمان تاریخ جهانی زمان جهانی را بکار U

می برد.

Monday, January

19،2004 21:05:20 PM

Montag, 19.

,Januar

21:05:20 2004

به عنوان آرگومان DateTime دستورات زیر تعدادی مثال فرمت دهی تاریخ را نشان می دهند. در هر کدام، یک شی از نوع

به یک رشته ی فرمت رد می شود.

DateTime curDate = DateTime.Now; // Get Current Date

Console.Writeline("Date: {0:d} ", curDate); // 1/19/2004

// f: --> Monday, January 19, 2004 5:05 PM

Console.Writeline("Date: {0:f} ", curDate);

// g: --> 1/19/2004 5:05 PM

Console.Writeline("Date: {0:g} ", curDate);

اگر هیچ کدام از علائم استاندارد فرمت نیاز شما را برآورده نسازد، می توانید یک فرمت سفارشی را با یک دنباله از

6، چند نمونه مفید در فرم تدهی تاری خها را لیست می کند. - کاراکترهای زیر ایجاد کنید. جدول 20

6- جدول 20

فرمت توصیف

روز ماه. صفر اضافی وجود ندارد. d

روز ماه. همیشه دو رقم وجود دارد. dd

روز هفته. با سه کاراکتر اختصار ddd

نام کامل روز هفته dddd

عدد ماه. بدون صفر اضافی M

عدد ماه. همیشه دو رقم دارد MM

نام ماه با سه حرف اختصار MMM

نام کامل ماه MMMM

یک یا دو رقم آخر سال y

یک یا دو رقم آخر سال. در صورت نیاز صفر اضافی قرار می گیرد. yy

اسلام احمد زاده - 09177112161 - C# برنامهنویسی

352

چهار رقم سال yyyy

ساعت در فرمت 24 ساعتی HH

دقیقه. در صورت نیاز با صفرهای اضافی mm

اینها مثال هایی از فرم تهای سفارشی تاریخ هستند.

DateTime curDate = DateTime.Now;

f = String.Format("{0:dddd} {0:MMM} {0:dd}", curDate);

// output: Monday Jan 19

f = currDate.ToString("dd MMM yyyy")

// output: 19 Jan 2004

// The standard short date format (d) is equivalent to this:

Console.WriteLine(currDate.ToString("M/d/yyyy")); // 1/19/2004

Console.WriteLine(currDate.ToString("d")); // 1/19/2004

CultureInfo ci = new CultureInfo("de-DE"); // German

f = currDate.ToString("dd-MMMM-yyyy HH:mm", ci)

// output: 19-Januar-20MQ 23:07

ترجیح داده می شود. آن گرامر مناسبی برای تعبیه String.Format به ToString در فرمت دهی سفارشی تاریخ، متد

فضاهای خالی و جداکنند ههای خاص مابین عناصر تاریخ دارد. به علاوه، پارامتر دوم آن یک مشخص کننده فرهنگ است.

-4 تاریخ ها و فرهنگ -6-20

.NET در سراسر جهان، تاریخ ها به روش های مختلفی نمایش داده می شوند. توانایی اضافه کردن فرهنگ در فرمت دهی توسط

است، به طور اتوماتیک تاری خها German ، بارکاری توسع هدهنده را کاهش داده است. برای مثال، اگر فرهنگ سیستم شما

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

مشخص می شود. این مثال . Januar19Montag, 19 به صورت Monday , January می شوند (به جای /) و عبارت

به کار می برد. German با فرهنگ CultureInfo را با پارامتر ToString متد

CultureInfo ci = new CultureInfo("de-DE"); // German

Console.WriteLine(curDate.ToString("D",ci));

// output ---> Montag, 19. Januar 2004

Console.WriteLine(curDate.ToString("dddd",ci)); // -->Montag

را برای چاپ کردن نام کامل روز هفته بکار می رود. این فرمت در برابر خصوصیت ”dddd“ آخرین دستور فرمت سفارشی

است که فقط یک مقدار انگلیسی بر می گرداند. DateTime.DayOfWeek شمارشی

NumberFormatInfo و DateTimeFormatInfo کلاس های

این دو کلاس نحوة اعمال فرم تهای بیان شده قبلی روی تاری خها و اعداد را مدیریت م یکنند. برای مثال، کلاس

خصوصیاتی دارد که کاراکتر سمبل پول، کاراکتر جدا کنندة دهدهی و تعداد ارقام دهدهی برای NumberFormatInfo

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

FullDateTimePattern طور مجازی با همه علائم استاندارد فرمت تاریخ ها یکسان هستند. به عنوان مثال، خصوصیت

برای فرمت دهی تاریخ م یباشد. F می باشد که معادل علامت فرمت

با فرهنگ های خاص مرتبط هستند و خصوصیات آنها DateTimeFormatInfo و NumberFormatInfo کلاس های

یک مجموعهی از پیش تعریف .NET . وسیله ای برای ایجاد فرم تهای منحصر به فرد مورد نیاز فرهن گهای مختلف هستند

کرد. override شده از مقادیر خصوصیت برای هر فرهنگی فراهم می کند، که نمیتوان آنها را

#C فصل بیستم دستکاری متن دز

353

بر اساس این که آیا فرهنگ جاری یا غیره ارجاع می شوند، این خصوصیات می توانند به رو شهای مختلفی دستیابی شوند.

دستورات زیر به فرهنگ جاری ارجاع دارند.

NumberFormatInfo.CurrentInfo.<property>

CultureInfo.CurrentCulture.NumberFormat.<property>

را بکار م یبرد و قطعاً فرهنگ جاری را بکار میبرد. دستور دوم یک فرهنگ CurrentInfo دستور اول خصوصیت ایستای

مناسب است. CultureInfo را بطور صریح مشخص می کند و برای دسترسی به خصوصیات فرهنگ دیگر یک نمونه از

CultureInfo ci = new CultureInfo("de-DE");

string f = ci.NumberFormat.CurrencySymbol;

که در ارتباط با فرهنگ غیر جاری هستند، DateTimeFormatInfo و NumberFormatInfo خصوصیاتی از کلا سهای

3 یک نمونه از نحوهی کار با این کلاس ها را پیشنهاد می کند - می توانند تغییر یابند. قطعه کد 20

3- قطعه کد 20

using System

using System.Globalization

Class MyApp

// NumberFormatInfo

string curSym = NumberFormatInfo.CurrentInfo.CurrencySymbol;

int dd = NumberFormatInfo.CurrentInfo.CurrencyDecimalDigits;

int pdd = NumberFormatInfo.CurrentInfo.PercentDecimalDigits;

// --> curSym = "$" dd = 2 pdd = 2

// DateTimeFormatInfo

string ldp= DateTimeFormatInfo.CurrentInfo.LongDatePattern;

// --> ldp = "dddd, MMMM, dd, yyyy"

string enDay = DateTimeFormatInfo.CurrentInfo.DayNames[1];

string month = DateTimeFormatInfo.CurrentInfo.MonthNames[1];

CultureInfo ci = new CultureInfo("de-DE");

string deDay = ci.DateTimeFormat.DayNames[1];

// --> enDay = "Monday" month = February deDay = "Montag"

// Change the default number of decimal places

// in a percentage

decimal passRate = .840M;

Console.Write(passRate.ToString("p",ci)); // 84,00%

ci.NumberFormat.PercentDecimalDigits = 1;

Console.Write(passRate.ToString("p",ci)); // 84,0%

}

برای برآورده ک ر دن نیاز شما به فرم ت دهی تاریخ ها و اعداد، الگوهای متنوعی را پیشنهاد م ی کند . برای NET. ، خلاصه اینکه

وجود دارند که سمب ل ها و قوانین مورد استفاده در DateTimeFormatInfo و NumberFormatInfo این منظور دو کلاس

به ازای هر فرهنگ خصوصیات فرمت خاص آن را فراهم کرده است. NET. . فرمت دهی را تعریف می کنند

-7-20 عبارات منظم

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

Grep . تأثیر گذاشت Unix در محیط Grep برای بیان هدف دستکاری رشته و متن طراحی شد. آن بر روی ابزار SNOBOL

یا هر زبان اسکریپتی دیگر کار کرد هاند، شباهت Perl یا Grep کاربرد عبارات منظم را گسترده ساخت. همهی آنهایی که با

را تشخیص خواهند داد. NET. پیاده سازی عبارات منظم در

تطابق الگو بر اساس مفهوم سادهی اعمال یک الگوی رشت های خاص به متون، برای تطابق یک نمونه یا نمونه هایی از آن الگو

بیان می گردد. Regex در متن است. بر خلاف متن، الگوی اعمال شده یک عبارت منظم یا به اختصار

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

354

Regex -1-7-20 کلاس

به عنوان موتور ارزیابی عبارات منظم است و الگوها را به رشته های هدف اعمال می کند. این کلاس Regex فرض کنید کلاس

متدهای ایستا و نمونه فراهم می کند که عبارات منظم را برای جستجوی متن، استخراج و جایگذاری بکار م یبرند. کلاس

یافته می شوند. System.Text.RegualarExpressions و همهی کلاس های مرتبط با آن، در فضای نامی Regex

گرامر

Regex( string pattern )

Regex( string pattern, RegexOptions)

پارامترها:

عبارت منظم برای تطابق الگو : Pattern

یک نوع شمارشی که مقادیر آن نحوهی اعمال عبارت منظم را کنترل می کند. مقادیر آن عبارتند از: :Regex Options

از فرهنگ صرفنظر می کند. -CultureInvariant

از حالت حروف صرفنظر می کند. – IgnoreCase

رشته را از چپ به راست پردازش می کند. – RightToLeft

مثال:

Regex r1 = new Regex(" "); // Regular expression is a blank

String words[] = r1.Split("red blue orange yellow");

// Regular expression matches upper- or lowercase "at"

Regex r2 = new Regex("at", RegexOptions.IgnoreCase);

کاملاً ساده است. اولین پارامتر سازنده یک عبارت منظم است. Regex همانطور ____________که مثال نشان می دهد، ایجاد یک شی

است که نحوهی اعمال عبارت منظم را کنترل می کند. RegexOptions پارامتر اختیاری دوم، یک یا چند مقدار شمارشی

Regex متدهای

Matches و Match ،Split ،Replace ،IsMatch تعدادی متد برای تطابق الگو و دستکاری متن دارد. آنها Regex کلاس

های ایستا و نمونه ای دارند که شبیه هستند، اما یکسان نیستند. Overload را شامل هستند. آنها

موثرتر است. زمانی که شی ایجاد می شود، آن Regex اگر بخواهید یک عبارت منظم را مکرراً بکار برید، ایجاد یک ش ی

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

ایستا در زمان استفادهی عبارت، آن را مجدداً کامپایل می کنند.

را بررسی کنیم. در این مثال ها، هدف معرفی متدهای عبارت های منظم است. به Regex حال اجازه دهید برخی از متدهای

همین دلیل از مثا لهای ساده استفاده می شود.

()IsMatch

این متد عبارت منظم را با یک رشته ورودی مطابقت می دهد و یک مقدار بر می گرداند. این مقدار مشخص می کند، آیا یک

تطابق پیدا شده است.

string searchStr = "He went that a way";

Regex myRegex = new Regex("at");

// instance methods

bool match = myRegex.IsMatch(searchStr); // true

// Begin search at position 12 in the string

match = myRegex.IsMatch(searchStr,12); // false

#C فصل بیستم دستکاری متن دز

355

// Static Methods – both return true

match = Regex.IsMatch(searchStr,"at");

match = Regex.IsMatch(searchStr,"AT",RegexOptions.IgnoreCase);

()Replace

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

برای مشخصکردن محل شروع جستجو و تعداد جایگزین یها دارد. overload

گرامر

static Replace (string input, string pattern, string replacement

[,RegexOptions])

Replace(string input, string replacement)

Replace(string input, string replacement, int count)

Replace(string input, string replacement, int count, int startat)

محل شروع عمل جستجوی تطابق ها را نشان می دهد. StartAt . حداکثر تعداد تطبی قها را مشخص میکند Count پارامتر

را می پذیرد. هر وقت یک تطابق پیدا شود، این MatchEvaluator این متد نسخ ههای مختلفی دارد که یک پارامتر نماینده

نماینده فراخوانی می شود و می تواند برای سفارشیکردن پروسهی جایگزینی استفاده شود.

قطعه کد زیر شک لهای ایستا و نمونه متد را ارائه می کند.

string newStr;

newStr = Regex.Replace("soft rose","o","i"); // sift rise

// instance method

Regex myRegex = new Regex("o"); // regex = "o"

// Now specify that only one replacement may occur

newStr = myRegex.Replace("soft rose","i",1); // sift rose

()Split

()String.Split این عمل رشته را با توجه به مح لهای تطابق یافته شده به یک آرایه تفکیک می کند. آن شبیه متد

است، با این استثناء که تطابق به جای یک کاراکتر با رشتهی کاراکتری و بر اساس یک عبارت منظم انجام میشود.

گرامر

String[] Split(string input)

String[] Split(string input, int count)

String[] Split(string input, int count, int startat)

Static String[] Split(string input, string pattern)

پارامترها

رشته مورد نظر جهت تفکیک :Input

حداکثر تعداد عناصر آرایه، مقدار صفر هر تعداد عنصر را ممکن می سازد. اگر تعداد تطابق ها از حداکثر بیشتر باشد، :Count

آخرین بخش مابقی رشته را در بر دارد.

محل شروع جستجو در رشتهی ورودی را مشخص م یکند. :Startat

الگوی عبارت منظم برای تطبیق با رشته ورودی است. :Pattern

مثال کوتاه زیر یک رشته شامل لیستی از اسامی هنرمندان را تجزیه کرده و در یک آرایه قرار می دهد. یک کاما و به دنبال

آن صفر یا چند فضای خالی اسامی را از هم جدا می کند. عبارت منظم برای تطبیق این جداساز",[ ]*" است. نحوهی ایجاد

این عبارت را بعداً خواهید دید.

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

356

// Regex to match a comma followed by 0 or more spaces

string patt = @",[ ]*";

// Static method

string[] artists = Regex.Split(impressionists, patt);

// Instance method is used to accept maximum of four matches

Regex myRegex = new Regex(patt);

string[] artists4 = myRegex.Split(impressionists, 4);

foreach (string master in artists4)

Console.Write(master);

// Output --> "Manet" "Monet" "Degas" "Pissarro,Sisley"

()Matches() , Match

واحد بر Match یک شی ()Match این متدها یک رشته ورودی را برای تطابق با عبارت منظم جستجو می کنند. متد

یک کلکسیون از همهی تطابق ها) را بر می گرداند. ) MatchCollection شی ()Matches می گرداند و متد

گرامر

Match Match(string input)

Match Match(string input, int startat)

Match Match(string input, int startat, int numchars)

static Match(string input, string pattern, [RegexOptions])

بر می گرداند. MatchCollection های مشابهی دارد، اما یک ش ی overload ،Matches() متد

بسیار غنی بوده و خصوصیاتی همچون رشته تطبیق Match هستند. شی Regex مفیدترین متدهای Matches و Match

دارد که شکستن یک الگوی تطبیق به چندین Groups شده، طول آن و محل آن در رشته ورودی را دارد. آن یک خصوصیت

را نشان می دهد. Match 7 اعضای انتخابی از کلاس - زیررشته تطبیقشده را مجاز می دارد. جدول 20

7- جدول 20

عضو توصیف

این خصوصیت محل اولین کاراکتر تطابق یافته در رشته را بر می گرداند. Index

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

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

قرار می گیرند.

طول رشتهی تطبیق شده Length

می باشد. false یا true ، وابسته به یافتن یک تطبیق Success

زیر رشتة تطبیق شده را بر می گرداند. Valve

جدید بر اساس کاراکترهای بعد از تطبیق قبلی بر م یگرداند. Match یک NextMatch

کد زیر کاربرد اعضای این کلاس را نشان م یدهد. توجه کنید که نقطه (.) در عبارت منظم به صورت یک کاراکتر عام

(جایگزینی) عمل می کند که با هر کاراکتری مطابقت دارد.

string verse = "In Xanadu did Kubla Khan";

string patt = ".an..."; // "." matches any character

Match verseMatch = Regex.Match(verse, patt);

#C فصل بیستم دستکاری متن دز

357

Console.WriteLine(verseMatch.Value); // Xanadu

Console.WriteLine(verseMatch.Index); // 3

//

string newPatt = "K(..)"; //contains group(..)

Match kMatch = Regex.Match(verse, newPatt);

while (kMatch.Success) {

Console.Write(kMatch.Value); // -->Kub -->Kha

Console.Write(kMatch.Groups[1]); // -->ub -->ha

kMatch = kMatch.NextMatch();

}

انتساب می دهد. kMatch را برای طیکردن سراسر رشتهی هدف بکار م یبرد و هر تطبیق را به NextMatch این مثال متد

بدون هیچ اثری روی الگوی اصلی آن را به گروه هایی تقسیم می کند. در این مثال، newPatt پرانتزهای دو طرف دو نقطه در

انتساب داده م یشوند. Groups به اشیاء K دو کاراکتر بعد از

بعضی اوقات ممکن است یک برنامه نیاز داشته باشد قبل از پردازش تطبی قها آنها را در یک کلکسیون جمع کند. این کار

است و با استفاده از متد Match است. این کلاس فقط یک ظرف برای نگه داشتن اشیاء MatchCollection هدف کلاس

یک عضو Item مفیدترین خصوصیت آن است و تعداد تطبی قها را بر می گرداند و Count . ایجاد می شود Regex.Matches

مثال قبلی آمده است. NextMatch واحد از کلکسیون را بر م یگرداند. در این جا روش دیگر نوشتن حلقهی

string verse = "In Xanadu did Kubla Khan";

String newpatt = "K(..)";

foreach (Match kMatch in Regex.Matches(verse, newpatt))

Console.Write(kMatch.Value); // -->Kub -->Kha

// Could also create explicit collection and work with it.

MatchCollection mc = Regex.Matches(verse, newpatt);

Console.WriteLine(mc.Count); // 2

-2-7-20 ایجاد عبارات منظم

استفاده شده اند، فقط عبارت های منظم ابتدایی را بکار گرفتند. حال، Regex مثال هایی که تا به حال برای ارائه متدهای

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

را با پروسه آزمایش و خطا کشف خواهید کرد. البته تقریباً همه الگوهای عمومی مورد استفاده روی یک سایت وب یافته

.(www.regexlib.com) را نگه می دارد Regex می شود. این سایت یک کتابخانة قابل جستجو از الگوهای

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

هر رقم از 0 تا 9 را تطبیق م یدهد. d\ کاراکترهای تطبیق: اینها یک نوع خاصی از کاراکتر را تطبیق م یدهند. برای مثال

برای d\d\d\ 3} می تواند به جای d{\ : کاراکترهای تکرار: از تکرار یک کاراکتر یا عنصر تطبیقی جلوگیری می کند. برای مثال

سه رقم تطبیقی استفاده شود.

3} لازم است تطبیق در d{\^ : کاراکترهای موقعیتی: محلی از رشتهی مقصد که یک تطبیق در آنجا باید رخ دهد. برای مثال

ابتدای رشته رخ دهد.

کاربرد \ قبل از یک کاراکتر مفهوم خاصی م یرساند. برای مثال \} اجازه می دهد کروشهی بسته در :Escape کاراکترهای

رشته تطبیق باشد.

8 الگوهای معروف را خلاصه می کند. - جدول 20

8- جدول 20

الگو معیار تطبیق مثال

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

358

+ یک یا چند رخداد از عنصر قبلی را تطبیق

می دهد.

را تطبیق می دهد. tooo و too عبارات to+

را تطبیق دهد. t آن نمی تواند

٭ صفر یا چند رخداد از عنصر قبلی را تطبیق

می دهد.

را تطبیق tooo ،too ،t رشته های *To

می دهد.

؟ صفر یا یک رخداد از عنصر قبلی را تطبیق

می دهد. تطبیق غیر حریصانه را انجام می دهد.

را تطبیق tn یا ten رشتههای Te?n

را نم یتواند تطبیق دهد. Teen . می دهد

رخداد از کاراکتر قبلی را تطبیق n دقیقاً {n}

می دهد.

را تطبیق م یدهد. teen رشتههای Te{2}n

را تطبیق نمی دهد. teeen یا Ten

رخداد از کاراکتر قبلی را تطبیق n حداقل {,n}

می دهد.

را تطبیق teen و ten رشته های {,Te{1

را تطبیق نم یدهد. tn . می دهد

رخداد کاراکتر قبلی را m و حداکثر n حداقل {n,m}

تطبیق می دهد.

را تطبیق teen و Ten رشتههای te{1،2}n

می دهد.

\ کاراکتر بعدی را به صورت حرف در نظر

می گیرد. در مورد کاراکترهایی که معنای

و ؟ + ،α خاصی دارند استفاده می شوند.مانند

را تطبیق می دهد. چون + A+B رشته ،A\+B

معنی خاصی دارد \ لازم است.

d\

D\

را تطبیق (D\) یا غیر رقم ( d\) هر تعداد رقم

- 9] یا [ 0 - می دهد. اینها به ترتیب معادل [ 0

98 ] هستند.

رشته ی 55 را تطبیق م یدهد. d\d\

را تطبیق م یدهد. XX رشته ی ، D\D\

w\

W\

هر کلمه را به همراه زیر خط تطبیق می دهد. و

a-] با w\ . موارد دیگر را تطبیق می دهد W\

a-zA-^] با W\ 9-0 _] معادل است و zA-Z

9-0 _] معادل است. Z

19 را تطبیق م یدهد. A_ ،w\w\w\w\

را تطبیق می دهد. ($) ، W\W\W\

n \r\

t \v\

f\

به ترتیب خط جدید، کاراکتر بازگشت، پرش

افقی، پرش عمودی یا صفحه جدید را تطبیق

می دهد.

s\

S\

هر S\ هر تعداد کاراکتر فضای خالی و s\

تعداد کاراکتر غیر فضای خالی را تطبیق

tab یا Space می دهد. فضای خالی یک

است.

را تطبیق A B C , \w\S\w\S\w

می دهد.

0(نقطه) هر کاراکتر واحد را تطبیق م یدهد. خط جدید

را تطبیق نم یدهد.

را تطبیق می دهد. ولی Abc رشته ی a.c

را تطبیق نم یدهد. abcc

را تطبیق م یدهد. ”enquiry “in|en منطقی OR |

0 ] هر کاراکتر داخل کروشهها را تطبیق میدهد. 0 0]

از خط تیره برای مشخص کردن محدوده

یک [d\D\] . را تطبیق می دهد aeiou] u]

رقم یا یک غیر رقم را تطبیق م یدهد.

#C فصل بیستم دستکاری متن دز

359

می توان استفاده کرد.

0 0 0] 8 ] همه کاراکترها به استثناء کاراکترهای داخل

کروشه را تطبیق م یدهد.

aeiou ] 8 را تطبیق م یدهد. x ،]

یک مثال تطابق الگو

این الگوهای کاراکتری را برای ایجاد یک عبارت منظم جهت تطبیق یک شماره تأمین اجتماعی اعمال کنید.

bool iMatch = Regex.IsMatch("245-09-8444",@"\d\d\d-\d\d-\d\d\d\d");

این یک روش بسیار سر راست است، که هر کاراکتر شماره تأمین اجتماعی با یک کاراکتر در عبارت منظم تطابق دارد. آن

ساده به نظر می رسد، ولی در رشته های بلند تکرار این کاراکترها مزاحمت ایجاد می کند. کاراکترهای تکرار این عمل را بهبود

می دهند.

bool iMatch = Regex.IsMatch("245-09-8444",@"\d{3}-\d{2}-\d{4}");

می توانیم محدودیت های دیگری روی شماره تأمین اجتماعی بررسی کنیم. ممکن است بخواهید مطمئن شوید، آن روی یک

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

فرض کنید، می خواهیم مطمئن شویم شماره تأمین اجتماعی فقط روی یک خط باشد. برای انجام این کار دو کاراکتر لازم

داریم. یکی برای اطمینان از اینکه تطبیق در ابتدای خط است و دیگری برای اطمینان از اینکه تطبیق در انتهای خط است. با

9 کاراکترهای 8 و $ در عبارت منظم برای برآوردن این شرط می توانند استفاده شوند. رشته ____________جدید به - توجه به جدول 20

صورت زیر خواهد بود.

@"^\d{3}-\d{2}-\d{4}$"

9- جدول 20

کاراکتر موقعیت توصیف

^ الگوی بعد از آن باید در ابتدای رشته یا خط باشد.

$ الگوی قبل از آن باید در انتهای خط یا انتهای رشته باشد.

الگوی قبل از آن باید در ابتدای یک رشته باشد. A\

تا مرز یک کلمه حرکت میکند. که میتواند یک کاراکتر کلمه یا کاراکتر غیر کلمه b \B\

باشد.

یا در انتهای رشته قبل از یک خط جدید باشد. (Z\) الگو باید در انتهای رشته z \Z\

این کاراکترهای موقعیت، هیچ فضایی در عبارت نمی گیرند، آنها فقط محلی که باید تطابق رخ دهد را مشخص می کنند.

کاراکترهای مابین خط فاصله را به سه گروه تقسیم کنید. برای ایجاد گروه، ،SSN به عنوان یک بهبود نهایی روی الگوی

بخش های مورد نظر را در داخل پرانتزها قرار دهید. در این حالت می توانید هر بخش را به طور مستقل بررسی کنید. کد ساده

زیر این الگوی پیشنهادی را بکار می برد.

string ssn = "245-09-8444";

string ssnPatt = @"^(\d{3})-(\d{2})-(\d{4})$";

Match ssnMatch = Regex.Match(ssn, ssnPatt);

اسلام احمد زاده - 09177112161 - C# برنامهنویسی

360

if (ssnMatch.Success){

Console.WriteLine(ssnMatch.Value); // 245-09-8444

Console.WriteLine(ssnMatch.Groups.Count); // 4

// Count is 4 since Groups[0] is set to entire SSN

Console.Write(ssnMatch.Groups[1]); // 245

Console.Write(ssnMatch.Groups[2]); // 09

Console.Write(ssnMatch.Groups[3]); // 8444

}

ما حالا یک الگوی مفیدی داریم که کاراکترهای موقعیت، تکرار و گروه را استفاده کرده است. ابتدا یک الگوی ساده ایجاد

4 را - کردیم، سپس در چندین مرحله آن را بهبود دادیم. این روش معمول ایجاد عبارات منظم پیچیده است. (شکل 20

ببینید).

4- شکل 20

کار با گروه ها

همانطور که در مثال قبلی دیدیم، متن منتج شده از یک تطابق، با قرار دادن بخ شهای یک عبارت در داخل پرانتزها، به طور

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

می شود. این کلکسیون با یک آرایه از خانهی صفر اندی سگذاری می شود. عنصر صفر برای کل []Match.Groups کلکسیون

تطابق، عنصر 1 برای گروه اول، عنصر 2 برای گروه دوم و غیره هستند.

برای بکارگیری آسان گروه ها می توانید آنها را نام گذاری کنید. نام مورد نظر در داخل پرانتز و بعد از پرانتز باز قرار می گیرد،

است. برای مشاهدهی کاربرد این گرو هها، فرض کنید در یک رشته اسامی هفته و دماهای حداکثر و ؟<name> که گرامر آن

حداقل وجود دارد و می خواهیم آنها را تجزیه کنیم.

string txt ="Monday Hi:88 Lo:56 Tuesday Hi:91 Lo:61";

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

طی می کند و محتوای هر گروه را چاپ م یکند.

string rgPatt = @"(?<day>[a-zA-Z]+)\s*(?<temps>Hi:\d+\s*Lo:\d+)";

MatchCollection mc = Regex.Matches(txt, rgPatt); //Get matches

foreach(Match m in mc)

Console.WriteLine("{0} {1}",

m.Groups["day"],m.Groups["temps"]);

//Output: Monday Hi:88 Lo:56

// Tuesday Hi:91 Lo:61

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

منطقی است OR هدف (an|in|on) گرو هبندی در نظر گرفته شود، در داخل پرانتز بعد از پرانتز باز علامت :؟را قرار دهید. در

(an|in|on:?) : و گرو هبندی نیست، پس م ینویسیم

ارجاع به عقب یک گروه

#C فصل بیستم دستکاری متن دز

361

اغلب معمول است یک عبارت منظم ایجاد کنیم که یک تطابق بر اساس نتیجهی تطابق قبلی را شامل است. برای مثال، در

حین کنترل گرامر در پردازشگرهای کلمه، هر کلمه ای را که یک تکرار از کلم ههای قبلی باشند علامت می زنند. می توانیم یک

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

به عنوان بخشی از الگو است. برای فهم بیشتر کد زیر را ملاحظه کنید.

string speech = "Four score and and seven years";

patt = @"(\b[a-zA-Z]+\b)\s\1"; // Match repeated words

MatchCollection mc = Regex.Matches(speech, patt);

foreach(Match m in mc) {

Console.WriteLine(m.Groups[1]); // --> and

}

این کد فقط کلمات تکراری را تطبیق م یدهد. عبارت منظم را بررسی کنید.

متن/الگو توصیف

and and

@"(\b[a-zA-Z]+\b)\s

و فضای خالی دنبال می شود را تطبیق (b\) هر کلمه که با مرز یک کلمه

می دهد.

and and

1\

علامت ارجاع به عقب با یک \ که به دنبال آن شماره گروه قرار دارد

مشخص میشود و م یتوان به یک گروه ارجاع کرد. اثر آن درج مقدار

یک گروه تطبیق شده به داخل عبارت است.

است که به دنبال عبارت >k\ به جای شماره گروه می توانید اسم آن را بکار برید. گرامر این نوع ارجاع بصورت > نام گروه

منظم نوشته می شود:

patt = @"(?<word>\b[a-zA-Z]+\b)\s\k<word>";

-3-7-20 مثال هایی از کاربرد عبارات منظم

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

باید دو چیز از این مثا لها بفهمید. اینها روش های نامحدودی برای ایجاد عبار تها جهت حل یک مسئله واحد هستند و

بیشتر مسائل تطبیق الگو نکات ظریفی دارند که فوراً آشکار نمی شوند.

برای معکوس کردن کلمات Replace کاربرد

string userName = "Claudel, Camille";

userName = Regex.Replace( userName, @"(\w+),\s*(\w+)", "$2 $1" );

Console.WriteLine(userName); // Camille Claudel

ارجاع به این گرو هها را با قرار Replace عبارت منظم نام اول و آخر را به گرو ههای 1 و 2 انتساب می دهد. پارامتر سوم متد

دادن $ قبل از شماره گروه مجاز می دارد. در این مثال، نام کامل تطبیق شده با کلمات گروه 2 و به دنبال آن گروه 1 جایگزین

می گردد.

پارس کردن اعداد

String myText = "98, 98.0, +98.0, +98";

string numPatt = @"\d+"; // Integer

numPatt = @"(\d+\.?\d*)|(\.\d+)"; // Allow decimal

numPatt = @"([+-]?\d+\.?\d*)|([+-]?\.\d+)"; // Allow + or -

-

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

362

در خط سوم کد، برای پیشنهاد کردن چندین الگو است. در این مثال، وجود یک عدد (|) OR توجه کنید که کاربرد سمبل

اختیاری قبل از نقطه اعشار را مجاز م یدارد.

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

نرسیده، گروه تکرار شود. زمانی که این گروه اعمال گردد، آن یک عدد هگزا null کاراکتر ٭ باعث می شود تا زمانیکه به

قرار می گیرد. CaptureCollection دسیمال 4 رقمی را بر می دارد که در شی

string hex = "00AA001CFF0C";

string hexPatt = @"^(?<hex4>[a-fA-F\d]{4})*";

Match hexMatch = Regex.Match(hex,hexPatt);

Console.WriteLine(hexMatch.Value); // --> 00AA001CFFOC

CaptureCollection cc = hexMatch.Groups["hex4"].Captures;

foreach (Capture c in cc)

Console.Write(c.Value); // --> 00AA 001C FF0C

را نشان می دهد CaptureCollection و GroupCollection ,Match 5 رابطهی سلسله مراتبی مابین - شکل 5

5- شکل 20

-8-20 خلاصه

معرفی شدند، تقاضا برای کار با کاراکترها افزایش یافت. ANSI یا ASCII • از زمانیکه کاراکترهای 7بیتی

این استاندارد را با کاراکترهای NET. • امروزه یونیکد استاندارد نمایش بیش از 90000 کاراکتر را تعریف میکند. که

16 بیتی میپوشاند.

مفهوم محلی کردن را پشتیبانی میکند، یعنی رعایت اطلاعات فرهنگ ماشین محلی را تضمین میکند. NET. •

فراهم NET. در StringBuilder و String • ادارهکردن رشتهها با یک مجموعهی غنی از متدهای کلاسهای

شده است.

متدهای متنوعی برای مقایسهی رشتهها موجود است که حالت حروف و فرهنگ را در صورت نیاز در نظر میگیرند.

برای فرمتدهی نمایش اعداد، رشتهها، تاریخ و واحد پول و غیره استفاده میشود. String.Format • متد

استفاده StringBuilder • دستکاری رشتهها حافظه را زیاد مصرف میکنند، برای کاربرد کارای حافظه از کلاس

میکنند.

استفاده کرد. Regex • برای تطابق الگوها و پارس کردن رشتهها میتوان از کلاس

mohsen_mahyar@yahoo.com - C#   نویسی برنامه

 

   + MOHSEN GHASEMI - ۱٠:٥٠ ‎ب.ظ ; ۱۳۸٩/٤/٢۸

فصل نوزدهم اداره کردن استثناء در #C

<!-- /* Font Definitions */ @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:-1610611985 1107304683 0 0 159 0;} @font-face {font-family:Tahoma; panose-1:2 11 6 4 3 5 4 4 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:1627400839 -2147483648 8 0 66047 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"Times New Roman","serif"; mso-fareast-font-family:"Times New Roman";} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; font-size:10.0pt; mso-ansi-font-size:10.0pt; mso-bidi-font-size:10.0pt;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:35.4pt; mso-footer-margin:35.4pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

فصل نوزدهم

C# اداره کردن استثناء در

آنچه که در این فصل یاد خواهید گرفت:

با مفهوم استثناء و نحو هی مدیریت آن توسط سیتم عامل آشنا خواهید شد.

با نحوه ی کنترل استثناءهای برنامه توسط برنام هنویس آشنا خواهید شد.

را برای اداره کردن استثنا/ئ به کار خواهید برد. try/catch/finally • ساختار

پیش بینی نشده است ایجاد خواهید کرد. NET. • استثناءهای سفارشی جهت تولید پیام های مناسبی که در

-1-19 مقدمه

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

خاتمه ندهد. بدین معنی که باید یک برنامه با خطاهای زمان اجرا بصورت مطلوب رفتار نماید. اینکه آنها از خطای کد برنامه

یا خطاهای سختافزاری نشأت میگیرند. (FCL)

1 به منظور برخورد با شرایط خطا برای توسعهدهندگان (SEH) یک تکنیک بنام اداره کردن ساختیافتهی استثناء NET.

فراهم میسازد. هدف اصلی این است که،زمانی که یک استثناء رخ میدهد، یک شی استثناء ایجاد شده و کنترل برنامه به

شی استثناء از یک بخش به بخش دیگر که آن را درک میکند، منتقل ،NET. بخش خاصی از کد رد میشود. در اصطلاحات

میشود.

مزایای SEH ، در مقایسه با تکنیکهای اداره کردن خطا، که به کدهای خطا استناد میکنند و مقادیر بیتی را تنظیم میکنند

مهمی را پیشنهاد میکند:

استثناء همانند یک شی به برنامه رد میشود. خصوصیات آن، یک توصیف از استثناء، نام