5. کلاسهای پرکاربرد .NET
در اینجا چند کلاس پرکاربرد از پلتفرم .NET را معرفی میکنیم. پیش از آن، نشان میدهیم که چگونه میتوان اطلاعات مربوط به چند صد کلاس موجود را به دست آورد. این راهنما حتی برای توسعهدهندگان باتجربه C# نیز ضروری است. کیفیت مستندات (سهولت دسترسی، سازماندهی واضح، مرتبط بودن اطلاعات و غیره) میتواند یک محیط توسعه را بسازد یا نابود کند.
5.1. جستجوی راهنما برای کلاسهای .NET
در اینجا چند نکته برای یافتن راهنما در Visual Studio.NET ارائه شده است
5.1.1. راهنما/فهرست مطالب
![]() |
- در [1]، گزینه Help/Contents را از منو انتخاب کنید.
- در [2]، گزینه Visual C# Express Edition را انتخاب کنید
- در [3]، درخت راهنمای C#
- در [4]، گزینهٔ مفید دیگری .NET Framework است که دسترسی به تمام کلاسهای فریمورک .NET را فراهم میکند.
بیایید نگاهی به عناوین فصلها در راهنمای C# بیندازیم:
![]() |
- [1]: مروری بر C#
- [2]: مجموعهای از مثالها که جنبههای خاصی از C# را نشان میدهند
- [3]: یک دورهٔ C# – میتواند بهطور مفید این سند را جایگزین کند…
![]() |
- [4]: برای بررسی دقیقتر C#
- [5]: مفید برای توسعهدهندگان C++ یا Java. به شما کمک میکند از چند تله اجتناب کنید.
- [6]: وقتی به دنبال مثالها هستید، میتوانید از اینجا شروع کنید.
![]() |
- [7]: آنچه برای ایجاد رابطهای کاربری گرافیکی باید بدانید
- [8]: چگونه بیشترین بهره را از IDE ویژوال استودیو اکسپرس ببرید
![]() |
- [9]: SQL Server Express 2005 یک نرمافزار توزیعشده با کیفیت بالا است که بهصورت رایگان ارائه میشود. ما در این دوره از آن استفاده خواهیم کرد.
راهنمای C# تنها بخشی از نیاز یک توسعهدهنده است. بخش دیگر، راهنمای صدها کلاس در فریمورک .NET است که کار آنها را آسانتر میکند.
![]() |
- [1]: راهنمای فریمورک .NET را انتخاب کنید
- [2]: راهنما در شاخه Framework .NET قرار دارد SDK
- [3]: شاخهٔ کتابخانهٔ کلاسهای فریمورک .NET تمام کلاسها را .NET بر اساس فضای نامی که به آن تعلق دارند فهرست میکند
- [4]: فضای نام System که در مثالهای فصلهای قبلی بیشترین استفاده را داشت
![]() |
- [5]: در فضای نام System، یک مثال، در این مورد ساختار DateTime
![]() |
- [6]: راهنما درباره ساختار DateTime
5.1.2. راهنما/فهرست/جستجو
راهنمای ارائهشده توسط MSDN بسیار گسترده است و ممکن است ندانید کجا را جستجو کنید. در این صورت میتوانید از نمایه راهنما استفاده کنید:
![]() |
- در [1]، اگر پنجرهٔ راهنما هنوز باز نیست، از گزینهٔ [Help/Index] استفاده کنید؛ در غیر این صورت، در یک پنجرهٔ راهنمای موجود از [2] استفاده کنید.
- برای [3]، ناحیهای را که جستجو باید در آن انجام شود مشخص کنید
- در [4]، مشخص کنید که به دنبال چه چیزی هستید – در این مورد، یک کلاس
- در [5]، نتیجه
راه دیگری برای یافتن کمک، استفاده از قابلیت جستجوی کمک است:
![]() |
- در [1]، اگر پنجرهٔ راهنما هنوز باز نیست، از گزینهٔ [Help/Search] استفاده کنید؛ در غیر این صورت، در پنجرهٔ راهنمای موجود از [2] استفاده کنید.
- برای [3]، مشخص کنید که به دنبال چه چیزی هستید
- در [4]، حوزههای جستجو را فیلتر کنید
![]() |
- در [5]، نتایج به صورت موضوعات مختلف نمایش داده میشوند که متن جستجو شده در آنها یافت شده است.
5.2. رشتههای کاراکتری
5.2.1. کلاس System.String
![]() | ![]() | ![]() |
کلاس System.String با نوع رشته ساده یکسان است. این کلاس دارای خواص و متدهای متعددی است. در اینجا به چند مورد از آنها اشاره میشود:
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
توجه به این نکته مهم است که وقتی یک متد رشتهای را بازمیگرداند، این رشته با رشتهای که متد روی آن اعمال شده است متفاوت است. بنابراین، S1.Trim() رشته S2 را برمیگرداند، و S1 و S2 دو رشته متفاوت هستند.
یک رشته C را میتوان بهعنوان یک آرایه از کاراکترها در نظر گرفت. بنابراین
- C[i] کاراکتر i-ام C است
- C.Length تعداد کاراکترهای C است
مثال زیر را در نظر بگیرید:
using System;
namespace Chap3 {
class Program {
static void Main(string[] args) {
string uneChaine = "l'oiseau vole au-dessus des nuages";
affiche("uneChaine=" + uneChaine);
affiche("uneChaine.Length=" + uneChaine.Length);
affiche("chaine[10]=" + uneChaine[10]);
affiche("uneChaine.IndexOf(\"vole\")=" + uneChaine.IndexOf("vole"));
affiche("uneChaine.IndexOf(\"x\")=" + uneChaine.IndexOf("x"));
affiche("uneChaine.LastIndexOf('a')=" + uneChaine.LastIndexOf('a'));
affiche("uneChaine.LastIndexOf('x')=" + uneChaine.LastIndexOf('x'));
affiche("uneChaine.Substring(4,7)=" + uneChaine.Substring(4, 7));
affiche("uneChaine.ToUpper()=" + uneChaine.ToUpper());
affiche("uneChaine.ToLower()=" + uneChaine.ToLower());
affiche("uneChaine.Replace('a','A')=" + uneChaine.Replace('a', 'A'));
string[] champs = uneChaine.Split(null);
for (int i = 0; i < champs.Length; i++) {
affiche("champs[" + i + "]=[" + champs[i] + "]");
}//برای
affiche("Join(\":\",champs)=" + System.String.Join(":", champs));
affiche("(\" abc \").Trim()=[" + " abc ".Trim() + "]");
}//اصلی
public static void affiche(string msg) {
// پیام را نمایش میدهد
Console.WriteLine(msg);
}//نمایش میدهد
}//کلاس
}//فضای نام
اجرا نتایج زیر را تولید میکند:
بیایید مثال دیگری را در نظر بگیریم:
using System;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// خطی که باید تحلیل شود
string ligne = "un:deux::trois:";
//جداکنندههای فیلد
char[] séparateurs = new char[] { ':' };
// تفکیک
string[] champs = ligne.Split(séparateurs);
for (int i = 0; i < champs.Length; i++) {
Console.WriteLine("Champs[" + i + "]=" + champs[i]);
}
// الحاق
Console.WriteLine("join=[" + System.String.Join(":", champs) + "]");
}
}
}
و نتایج اجرا:
متد Split کلاس String امکان قرار دادن عناصر یک رشتهٔ کاراکتری در یک آرایه را فراهم میکند. تعریف متد Split که در اینجا استفاده شده به شرح زیر است:
public string[] Split(char[] separator);
آرایه کاراکتری. این کاراکترها نمایانگر کاراکترهای مورد استفاده برای جدا کردن فیلدها در رشته هستند. بنابراین، اگر رشته "champ1, champ2, champ3"" باشد، میتوانید از `separator=new char[] {','}` استفاده کنید. اگر جداکننده دنبالهای از فضاها باشد، از separator=null استفاده میکنیم. | |
یک آرایه از رشتهها که هر عنصر آن یک فیلد از رشته است. |
متد Join یک متد ایستا از کلاس String است:
public static string Join(string separator, string[] value);
آرایهٔ رشتهها | |
یک رشته برای استفاده به عنوان جداکننده فیلد | |
یک رشته که با الحاق عناصر آرایه value تشکیل شده و با رشته separator از هم جدا شدهاند. |
5.2.2. کلاس System.Text.StringBuilder
![]() | ![]() | ![]() |
قبلاً اشاره کردیم که متدهای کلاس String که بر روی یک رشته کاراکتری S1 اعمال میشوند، یک رشته دیگر S2 را بازمیگردانند. کلاس System.Text.StringBuilder به شما امکان میدهد S1 را بدون نیاز به ایجاد یک رشته S2 دستکاری کنید. این امر با جلوگیری از پراکنده شدن رشتههایی با چرخه عمر بسیار کوتاه، عملکرد را بهبود میبخشد.
این کلاس از سازندهای مختلفی پشتیبانی میکند:
| |
|
یک شیء StringBuilder با بلوکهای کاراکتری از نوع capacité برای ذخیرهٔ رشتهٔ زیربنایی کار میکند. بهطور پیشفرض، capacité روی 16 تنظیم شده است. سومین سازندهٔ بالا به شما امکان میدهد ظرفیت بلوکها را مشخص کنید. تعداد بلوکهای کاراکتری capacité مورد نیاز برای ذخیرهٔ رشتهٔ S بهطور خودکار توسط کلاس StringBuilder تنظیم میشود. سازندههایی برای تنظیم حداکثر تعداد کاراکترها در یک شیء StringBuilder وجود دارد. به طور پیشفرض، این حداکثر ظرفیت ۲٬۱۴۷٬۴۸۳٬۶۴۷ است.
در اینجا مثالی برای روشنسازی این مفهوم در capacité آورده شده است:
using System.Text;
using System;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// رشته
StringBuilder str = new StringBuilder("test");
Console.WriteLine("taille={0}, capacité={1}", str.Length, str.Capacity);
for (int i = 0; i < 10; i++) {
str.Append("test");
Console.WriteLine("taille={0}, capacité={1}", str.Length, str.Capacity);
}
// str2
StringBuilder str2 = new StringBuilder("test",10);
Console.WriteLine("taille={0}, capacité={1}", str2.Length, str2.Capacity);
for (int i = 0; i < 10; i++) {
str2.Append("test");
Console.WriteLine("taille={0}, capacité={1}", str2.Length, str2.Capacity);
}
}
}
}
- خط ۷: ایجاد یک شیء StringBuilder با اندازه بلوک ۱۶ کاراکتر
- خط ۸: str.Length تعداد فعلی کاراکترها در رشته str است. str.Capacity تعداد کاراکترهایی است که رشته فعلی str میتواند ذخیره کند قبل از تخصیص مجدد یک بلوک جدید.
- خط ۱۰: str.Append(String S) برای الحاق رشته S (از نوع String) به رشته str (از نوع StringBuilder) استفاده میشود.
- خط ۱۴: ایجاد یک شیء StringBuilder با ظرفیت بلوک ۱۰ کاراکتر
نتیجه اجرای کد:
این نتایج نشان میدهد که کلاس هنگام ناکافی بودن ظرفیت، از الگوریتم خاص خود برای تخصیص بلوکهای جدید پیروی میکند:
- خطوط ۴–۵: ظرفیت ۱۶ کاراکتری افزایش یافت
- خطوط ۸–۹: ظرفیت به ۳۲ کاراکتر افزایش یافت، در حالی که ۱۶ کاراکتر کافی بود.
در اینجا برخی از متدهای کلاس آورده شده است:
| |
| |
| |
| |
|
در اینجا یک مثال آورده شده است:
using System.Text;
using System;
namespace Chap3 {
class Program {
static void Main(string[] args) {
//str3
StringBuilder str3 = new StringBuilder("test");
Console.WriteLine(str3.Append("abCD").Insert(2, "xyZT").Remove(0, 2).Replace("xy", "XY"));
}
}
}
و نتایج آن:
5.3. آرایهها
آرایهها از کلاس Array مشتق شدهاند:
![]() | ![]() | ![]() |
کلاس Array دارای متدهای مختلفی برای مرتبسازی آرایه، جستجو برای یک عنصر در آرایه، تغییر اندازه آرایه و غیره است. ما برخی از ویژگیها و متدهای این کلاس را ارائه میدهیم. تقریباً همه آنها دارای بارگذاری مجدد (overloaded) هستند، c.a.d، به این معنی که در گونههای مختلفی وجود دارند. هر آرایه از این کلاس ارث میبرد.
ویژگیها
روشها
برنامه زیر کاربرد برخی از متدهای کلاس Array را نشان میدهد:
using System;
namespace Chap3 {
class Program {
// نوع جستجو
enum TypeRecherche { linéaire, dichotomique };
// روش اصلی
static void Main(string[] args) {
// خواندن عناصر آرایه وارد شده از طریق صفحهکلید
double[] éléments;
Saisie(out éléments);
// نمایش آرایه مرتبنشده
Affiche("Tableau non trié", éléments);
// جستجوی خطی در یک آرایه مرتبنشده
Recherche(éléments, TypeRecherche.linéaire);
//مرتبسازی آرایه
Array.Sort(éléments);
//نمایش یک آرایه مرتبشده
Affiche("Tableau trié", éléments);
//جستجوی دودویی در آرایه مرتبشده
Recherche(éléments, TypeRecherche.dichotomique);
}
// وارد کردن مقادیر برای عناصر آرایه
// عناصر: ارجاع به آرایهای که توسط متد ایجاد شده است
static void Saisie(out double[] éléments) {
bool terminé = false;
string réponse;
bool erreur;
double élément = 0;
int i = 0;
//در ابتدا آرایه وجود ندارد
éléments = null;
//حلقه برای وارد کردن عناصر آرایه
while (!terminé) {
// پرسوجو
Console.Write("Elément (réel) " + i + " du tableau (rien pour terminer) : ");
// خواندن پاسخ
réponse = Console.ReadLine().Trim();
// پایان ورودی اگر رشته خالی باشد
if (réponse.Equals(""))
break;
//اعتبارسنجی ورودی
try {
élément = Double.Parse(réponse);
erreur = false;
} catch {
Console.Error.WriteLine("Saisie incorrecte, recommencez");
erreur = true;
}//try-catch
// اگر خطایی وجود نداشته باشد
if (!erreur) {
// افزودن یک عنصر دیگر به آرایه
i += 1;
// تغییر اندازه آرایه برای جای دادن عنصر جدید
Array.Resize(ref éléments, i);
// افزودن عنصر جدید
éléments[i - 1] = élément;
}
}//در حالی که
}
// روش عمومی برای نمایش عناصر یک آرایه
static void Affiche<T>(string texte, T[] éléments) {
Console.WriteLine(texte.PadRight(50, '-'));
foreach (T élément in éléments) {
Console.WriteLine(élément);
}
}
// جستجو برای یک عنصر در آرایه
// عناصر: آرایهای از اعداد حقیقی
// TypeRecherche: دوگانه یا خطی
static void Recherche(double[] éléments, TypeRecherche type) {
//جستجو
bool terminé = false;
string réponse = null;
double élément = 0;
bool erreur = false;
int i = 0;
while (!terminé) {
// سؤال
Console.WriteLine("Elément cherché (rien pour arrêter) : ");
// خواندن و بررسی پاسخ
réponse = Console.ReadLine().Trim();
// تمام شد؟
if (réponse.Equals(""))
break;
//بررسی
try {
élément = Double.Parse(réponse);
erreur = false;
} catch {
Console.WriteLine("Erreur, recommencez...");
erreur = true;
}//try-catch
// اگر خطا وجود نداشته باشد
if (!erreur) {
// جستجو برای عنصر در آرایه
if (type == TypeRecherche.dichotomique)
// جستجوی دودویی
i = Array.BinarySearch(éléments, élément);
else
// جستجوی خطی
i = Array.IndexOf(éléments, élément);
// نمایش نتیجه
if (i >= 0)
Console.WriteLine("Trouvé en position " + i);
else
Console.WriteLine("Pas dans le tableau");
}//اگر
}//در حالی که
}
}
}
- خطوط ۲۷–۶۲: متد Saisie عناصر آرایه éléments را که از طریق صفحهکلید وارد شدهاند، دریافت میکند. از آنجا که نمیتوان اندازه آرایه را از پیش تعیین کرد (اندازه نهایی آن نامشخص است)، هر بار که عنصر جدیدی اضافه میشود باید اندازه آن تغییر کند (خط ۵۷). الگوریتم کارآمدتری این بود که فضا را برای آرایه به صورت گروههای N عنصری تخصیص میداد. با این حال، آرایه برای تغییر اندازه طراحی نشده است. این سناریو بهتر است با استفاده از یک لیست (ArrayList, List<T>) مدیریت شود.
- خطوط ۷۵–۱۱۳: متد Recherche امکان جستجو در آرایه éléments را برای عنصری که از طریق صفحهکلید وارد شده است، فراهم میکند. روش جستجو بسته به مرتب بودن یا نبودن آرایه متفاوت است. برای آرایهای که مرتب نشده است، یک جستجوی خطی با استفاده از روش IndexOf در خط ۱۰۶ انجام میشود. برای آرایهای که مرتب شده است، یک جستجوی دودویی با استفاده از روش BinarySearch در خط ۱۰۳ انجام میشود.
- خط ۱۸: آرایه éléments مرتب شده است. در اینجا، از یک واریانت از Sort استفاده میشود که تنها یک پارامتر دارد: آرایهای که باید مرتب شود. بنابراین رابطه مرتبسازی مورد استفاده برای مقایسه عناصر آرایه، رابطه ضمنی برای این عناصر است. در اینجا، عناصر عددی هستند. از مرتبسازی طبیعی اعداد استفاده میشود.
خروجی صفحه به شرح زیر است:
5.4. مجموعههای عمومی
علاوه بر آرایهها، کلاسهای مختلفی برای ذخیرهسازی مجموعههای عناصر وجود دارند. نسخههای عمومی در فضای نام System.Collections.Generic در دسترس هستند، در حالی که نسخههای غیرعمومی در System.Collections موجودند. ما به دو مجموعه عمومی پرکاربرد میپردازیم: لیست و فرهنگ لغت.
فهرست مجموعههای عمومی به شرح زیر است:

5.4.1. کلاس عمومی List<T>
کلاس System.Collections.Generic.List<T> امکان پیادهسازی مجموعههایی از اشیاء از نوع T را فراهم میکند که اندازه آنها در حین اجرای برنامه تغییر میکند. یک شیء از نوع List<T> تقریباً مانند یک آرایه با آن برخورد میشود. بنابراین، عنصر i از یک لیست l با l[i] نشان داده میشود.
همچنین یک نوع لیست غیرکلی وجود دارد: ArrayList، که قادر به ذخیره ارجاع به هر شیئی است. ArrayList از نظر عملکردی معادل List<Object>. است. یک شیء ArrayList به این صورت است:
![]() |
در مثال بالا، عناصر 0، 1 و i در لیست به اشیایی با انواع مختلف اشاره میکنند. یک شیء باید ابتدا ایجاد شود تا مرجع آن بتواند به لیست ArrayList اضافه شود. اگرچه یک ArrayList مراجع اشیاء را ذخیره میکند، اما امکان ذخیره اعداد در آن نیز وجود دارد. این امر از طریق مکانیزمی به نام Boxing انجام میشود: عدد در درون یک شیء O از نوع Object قرار میگیرد و مرجع به O در لیست ذخیره میشود. این مکانیزم برای توسعهدهنده شفاف است. بنابراین میتوانیم بنویسیم:
این کار نتیجهٔ زیر را تولید میکند:
![]() |
در مثال بالا، عدد ۴ در یک شیء O بستهبندی شده و مرجع O در لیست ذخیره شده است. برای بازیابی آن میتوان نوشت:
int i = (int)liste[0];
عملیات Object -> int، Unboxing نامیده میشود. اگر یک لیست کاملاً از نوع int تشکیل شده باشد، اعلام آن به عنوان List<int> عملکرد را بهبود میبخشد. این به این دلیل است که اعداد از نوع int سپس در خود لیست ذخیره میشوند، نه در انواع Object که خارج از لیست قرار دارند. عملیات باکسینگ و آنباکسینگ دیگر انجام نمیشوند.
برای یک شیء از نوع List<T> یا T که یک کلاس است، لیست دوباره ارجاع به اشیاء از نوع T را ذخیره میکند:
![]() |
در اینجا برخی از ویژگیها و متدهای لیستهای عمومی آورده شده است:
ویژگیها
روشها
بیایید به مثال قبلی بازگردیم که شامل یک شیء از نوع Array بود و اکنون آن را با استفاده از یک شیء از نوع List<T>. پردازش کنیم. از آنجایی که این لیست شبیه به یک آرایه است، کد تغییر بسیار کمی دارد. ما فقط تغییرات قابل توجه را برجسته خواهیم کرد:
using System;
using System.Collections.Generic;
namespace Chap3 {
class Program {
// نوع جستجو
enum TypeRecherche { linéaire, dichotomique };
// روش اصلی
static void Main(string[] args) {
// اقلام فهرست مطالعه وارد شده از طریق صفحهکلید
List<double> éléments;
Saisie(out éléments);
// تعداد موارد
Console.WriteLine("La liste a {0} éléments et une capacité de {1} éléments", éléments.Count, éléments.Capacity);
//نمایش لیست مرتبنشده
Affiche("Liste non triée", éléments);
// جستجوی خطی در لیست مرتبنشده
Recherche(éléments, TypeRecherche.linéaire);
//مرتبسازی لیست
éléments.Sort();
//نمایش لیست مرتبشده
Affiche("Liste triée", éléments);
//جستجوی دودویی در لیست مرتبشده
Recherche(éléments, TypeRecherche.dichotomique);
}
// وارد کردن مقادیر از فهرست عناصر
// عناصر: ارجاع به لیستی که توسط متد ایجاد شده است
static void Saisie(out List<double> éléments) {
...
//در ابتدا، لیست خالی است
éléments = new List<double>();
//حلقه برای وارد کردن عناصر لیست
while (!terminé) {
...
// اگر خطایی رخ ندهد
if (!erreur) {
// یک مورد دیگر به فهرست اضافه کنید
éléments.Add(élément);
}
}//در حالی که
}
// روش عمومی برای نمایش عناصر یک شی قابل شمارش
static void Affiche<T>(string texte, IEnumerable<T> éléments) {
Console.WriteLine(texte.PadRight(50, '-'));
foreach (T élément in éléments) {
Console.WriteLine(élément);
}
}
// جستجو برای یک عنصر در لیست
// عناصر: فهرست اعداد حقیقی
// TypeRecherche: دوگانه یا خطی
static void Recherche(List<double> éléments, TypeRecherche type) {
...
while (!terminé) {
...
// اگر خطایی وجود نداشته باشد
if (!erreur) {
//جستجو برای عنصر در لیست
if (type == TypeRecherche.dichotomique)
// جستجوی دودویی
i = éléments.BinarySearch(élément);
else
// جستجوی خطی
i = éléments.IndexOf(élément);
// نمایش پاسخ
...
}//اگر
}//در حالی که
}
}
}
- خطوط ۴۶–۵۱: متد عمومی Affiche<T> دو پارامتر میگیرد:
- پارامتر اول متنی است که باید نوشته شود
- پارامتر دوم یک شیء است که رابط عمومی IEnumerable<T> را پیادهسازی میکند:
ساختار foreach( T element in elements) در خط ۴۸ برای هر شیء éléments که رابط IEnumerable را پیادهسازی میکند، معتبر است. آرایهها (Array) و لیستها (List<T>) رابط IEnumerable<T> را پیادهسازی میکنند. بنابراین متد Affiche به یک اندازه برای نمایش هر دو جدول و فهرستها مناسب است.
خروجی برنامه همانند مثالی است که از کلاس Array استفاده میکند.
5.4.2. کلاس Dictionary<TKey,TValue>
کلاس System.Collections.Generic.Dictionary<TKey,TValue> امکان پیادهسازی یک فرهنگ لغت را فراهم میکند. یک فرهنگ لغت را میتوان به عنوان یک آرایه دو ستونی در نظر گرفت:
کلید | value |
key1 | value1 |
key2 | value2 |
.. | ... |
در کلاس Dictionary<TKey,TValue>, کلیدها از نوع Tkey و مقادیر از نوع TValue هستند. کلیدها یکتا هستند، c.a.d، به این معنی که هیچ دو کلیدی نمیتوانند یکسان باشند. چنین دیکشنری ممکن است به این شکل به نظر برسد اگر انواع TKey و TValue نشاندهنده کلاسها باشند:
![]() |
مقدار مرتبط با کلید C در یک دیکشنری D با D[C] نشان داده میشود. این مقدار هم قابل خواندن و هم قابل نوشتن است. بنابراین، میتوان نوشت:
اگر کلید c در دیکشنری D وجود نداشته باشد، نشانه D[c] یک استثنا (exception) را پرتاب (throw) میکند.
روشها و ویژگیهای اصلی کلاس Dictionary<TKey,TValue> به شرح زیر است:
سازندهها
خواص
روشها
بیایید برنامهٔ مثال زیر را در نظر بگیریم:
using System;
using System.Collections.Generic;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// ایجاد یک دیکشنری <string,int>
string[] liste = { "jean:20", "paul:18", "mélanie:10", "violette:15" };
string[] champs = null;
char[] séparateurs = new char[] { ':' };
Dictionary<string,int> dico = new Dictionary<string,int>();
for (int i = 0; i <liste.Length; i++) {
champs = liste[i].Split(séparateurs);
dico[champs[0]]= int.Parse(champs[1]);
}//برای
//تعداد عناصر در فرهنگ لغت
Console.WriteLine("Le dictionnaire a " + dico.Count + " éléments");
// فهرست کلیدها
Affiche("[Liste des clés]",dico.Keys);
// فهرست مقادیر
Affiche("[Liste des valeurs]", dico.Values);
// فهرست کلیدها و مقادیر
Console.WriteLine("[Liste des clés & valeurs]");
foreach (string clé in dico.Keys) {
Console.WriteLine("clé=" + clé + " valeur=" + dico[clé]);
}
//کلید «paul» حذف شد
Console.WriteLine("[Suppression d'une clé]");
dico.Remove("paul");
// فهرست کلیدها و مقادیر
Console.WriteLine("[Liste des clés & valeurs]");
foreach (string clé in dico.Keys) {
Console.WriteLine("clé=" + clé + " valeur=" + dico[clé]);
}
// جستجو در فرهنگ لغت
String nomCherché = null;
Console.Write("Nom recherché (rien pour arrêter) : ");
nomCherché = Console.ReadLine().Trim();
int value;
while (!nomCherché.Equals("")) {
dico.TryGetValue(nomCherché, out value);
if (value!=0) {
Console.WriteLine(nomCherché + "," + value);
} else {
Console.WriteLine("Nom " + nomCherché + " inconnu");
}
// جستجوی بعدی
Console.Out.Write("Nom recherché (rien pour arrêter) : ");
nomCherché = Console.ReadLine().Trim();
}//در حالی که
}
// روش عمومی برای نمایش عناصر یک نوع قابل شمارش
static void Affiche<T>(string texte, IEnumerable<T> éléments) {
Console.WriteLine(texte.PadRight(50, '-'));
foreach (T élément in éléments) {
Console.WriteLine(élément);
}
}
}
}
- خط ۸: یک آرایه از string که برای مقداردهی اولیه فرهنگ لغت <string,int> استفاده خواهد شد
- خط ۱۱: دیکشنری <string,int>
- خطوط ۱۲–۱۵: مقداردهی اولیه آن با استفاده از آرایه string از خط ۸
- خط 17: تعداد موارد در فرهنگ لغت
- خط ۱۹: کلیدهای دیکشنری
- خط ۲۱: مقادیر فرهنگ لغت
- خط ۲۹: حذف یک مدخل از فرهنگ لغت
- خط ۴۱: جستجو برای یک کلید در دیکشنری. اگر وجود نداشته باشد، متد TryGetValue مقدار value را روی ۰ قرار میدهد، زیرا value از نوع عددی است. این تکنیک تنها در اینجا قابل استفاده است زیرا میدانیم مقدار 0 در دیکشنری وجود ندارد.
نتایج اجرا به شرح زیر است:
5.5. فایلهای متنی
5.5.1. کلاس StreamReader
کلاس System.IO.StreamReader به شما امکان میدهد محتوای یک فایل متنی را بخوانید. در واقع، این کلاس قادر است جریانهایی را که فایل نیستند نیز پردازش کند. در اینجا برخی از ویژگیها و متدهای آن آورده شده است:
سازندهها
خواص
روشها
در اینجا یک مثال آورده شده است:
using System;
using System.IO;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// دایرکتوری زمان اجرا
Console.WriteLine("Répertoire d'exécution : "+Environment.CurrentDirectory);
string ligne = null;
StreamReader fluxInfos = null;
// خواندن محتویات فایل infos.txt
try {
//خواندن ۱
Console.WriteLine("Lecture 1----------------");
using (fluxInfos = new StreamReader("infos.txt")) {
ligne = fluxInfos.ReadLine();
while (ligne != null) {
Console.WriteLine(ligne);
ligne = fluxInfos.ReadLine();
}
}
// خواندن ۲
Console.WriteLine("Lecture 2----------------");
using (fluxInfos = new StreamReader("infos.txt")) {
Console.WriteLine(fluxInfos.ReadToEnd());
}
} catch (Exception e) {
Console.WriteLine("L'erreur suivante s'est produite : " + e.Message);
}
}
}
}
- خط ۸: نام دایرکتوری اجرای برنامه را نمایش میدهد
- خطوط ۱۲ و ۲۷: یک بلوک try/catch برای رسیدگی به هرگونه استثنا.
- خط ۱۵: ساختار `using flux=new StreamReader(...)` یک ویژگی تسهیلی است تا شما مجبور نباشید پس از استفاده از استریم، آن را به صورت صریح ببندید. استریم به محض خروج از دامنه `using` به طور خودکار بسته میشود.
- خط ۱۵: فایلی که در حال خواندن است infos.txt نام دارد. از آنجایی که این یک مسیر نسبی است، در دایرکتوری اجرای نمایش داده شده در خط ۸ جستجو خواهد شد. اگر پیدا نشود، یک استثنا پرتاب شده و توسط بلاک try/catch مدیریت میشود.
- خطوط ۱۶–۲۰: فایل خط به خط خوانده میشود
- خط ۲۵: فایل یکجا خوانده میشود
فایل infos.txt به شرح زیر است:
و در پوشه زیر در پروژه C# قرار دارد:
![]() |
مشاهده خواهیم کرد که bin/Release پوشه خروجی است وقتی پروژه با استفاده از Ctrl-F5 اجرا میشود.
اجرای پروژه نتایج زیر را تولید میکند:
اگر در خط ۱۵ نام فایل xx.txt را وارد کنیم، نتایج زیر را دریافت میکنیم:
5.5.2. کلاس StreamWriter
کلاس System.IO.StreamReader به شما امکان میدهد در یک فایل متنی بنویسید. مانند کلاس StreamReader، در واقع قادر به مدیریت جریانهایی است که فایل نیستند. در اینجا برخی از ویژگیها و متدهای آن آورده شده است:
سازندهها
ویژگیها
روشها
بیایید مثال زیر را در نظر بگیریم:
using System;
using System.IO;
namespace Chap3 {
class Program2 {
static void Main(string[] args) {
// دایرکتوری اجرای برنامه
Console.WriteLine("Répertoire d'exécution : " + Environment.CurrentDirectory);
string ligne = null; //یک خط متن
StreamWriter fluxInfos = null; // فایل متنی
try {
// ایجاد فایل متنی
using (fluxInfos = new StreamWriter("infos2.txt")) {
Console.WriteLine("Mode AutoFlush : {0}", fluxInfos.AutoFlush);
// خواندن یک خط تایپشده روی صفحهکلید
Console.Write("ligne (rien pour arrêter) : ");
ligne = Console.ReadLine().Trim();
// حلقه تا زمانی که خط وارد شده خالی نباشد
while (ligne != "") {
//نوشتن یک خط در فایل متنی
fluxInfos.WriteLine(ligne);
//خواندن خط جدید از صفحهکلید
Console.Write("ligne (rien pour arrêter) : ");
ligne = Console.ReadLine().Trim();
}//در حالی که
}
} catch (Exception e) {
Console.WriteLine("L'erreur suivante s'est produite : " + e.Message);
}
}
}
}
- خط ۱۳: بار دیگر، از دستوری با سینتکس using(flux) استفاده میکنیم تا مجبور نباشیم جریان را بهصورت صریح با استفاده از عملیات Close ببندیم. این بستن بهطور خودکار هنگام خروج از using انجام میشود.
- چرا در خطوط ۱۱ و ۲۷ از بلوک try/catch استفاده میکنیم؟ در خط ۱۳ میتوانستیم نام فایل را به صورت /rep1/rep2/ .../ مشخص کنیم.fichier با مسیری /rep1/rep2/... که وجود ندارد، و در نتیجه ایجاد fichier غیرممکن میشود. سپس یک استثنا پرتاب (throw) میشود. سناریوهای استثنای دیگری نیز وجود دارد (پر شدن دیسک، مجوزهای ناکافی و غیره).
نتایج اجرا به شرح زیر است:
فایل infos2.txt در پوشه bin/Release پروژه ایجاد شد:
![]() | ![]() |
5.6. فایلهای باینری
کلاسهای System.IO.BinaryReader و System.IO.BinaryWriter برای خواندن و نوشتن فایلهای باینری استفاده میشوند.
برنامه زیر را در نظر بگیرید:
// pg نحو: متن، باینری، لاگها
//یک فایل متنی (text) را بخوانید و محتویات آن را در یک فایل باینری (bin) ذخیره کنید
// فایل متنی شامل خطوطی به شکل نام : سن است که در ساختاری متشکل از یک رشته و یک عدد صحیح ذخیره خواهد شد
//(logs) یک فایل لاگ متنی است
فایل متنی حاوی موارد زیر است:
برنامه به شرح زیر است:
using System;
using System.IO;
// سینتکس pg متن باینری لاگها
//یک فایل متنی (text) خوانده میشود و محتویات آن در یک فایل دودویی (bin) ذخیره میشود
// فایل متنی شامل خطوطی به شکل نام: سن است که در ساختاری شامل یک رشته و یک عدد صحیح ذخیره خواهد شد
//(logs) یک فایل لاگ متنی است
namespace Chap3 {
class Program {
static void Main(string[] arguments) {
//سه آرگومان لازم است
if (arguments.Length != 3) {
Console.WriteLine("syntaxe : pg texte binaire log");
Environment.Exit(1);
}//اگر
//متغیرها
string ligne=null;
string nom=null;
int age=0;
int numLigne = 0;
char[] séparateurs = new char[] { ':' };
string[] champs=null;
StreamReader input = null;
BinaryWriter output = null;
StreamWriter logs = null;
bool erreur = false;
// خواندن یک فایل متنی – نوشتن یک فایل باینری
try {
// باز کردن فایل متنی برای خواندن
input = new StreamReader(arguments[0]);
//باز کردن فایل باینری برای نوشتن
output = new BinaryWriter(new FileStream(arguments[1], FileMode.Create, FileAccess.Write));
// باز کردن فایل لاگ برای نوشتن
logs = new StreamWriter(arguments[2]);
// پردازش فایل متنی
while ((ligne = input.ReadLine()) != null) {
// یک خط دیگر
numLigne++;
// خط خالی؟
if (ligne.Trim() == "") {
// نادیده گرفته شد
continue;
}
// یک خط شامل: نام : سن
champs = ligne.Split(séparateurs);
// ما به دو فیلد نیاز داریم
if (champs.Length != 2) {
// خطا را ثبت کن
logs.WriteLine("La ligne n° [{0}] du fichier [{1}] a un nombre de champs incorrect", numLigne, arguments[0]);
// خط بعدی
continue;
}//اگر
// میدان اول نباید خالی باشد
erreur = false;
nom = champs[0].Trim();
if (nom == "") {
// خطا را ثبت کن
logs.WriteLine("La ligne n° [{0}] du fichier [{1}] a un nom vide", numLigne, arguments[0]);
erreur = true;
}
// دومین فیلد باید یک عدد صحیح ≥ 0 باشد
if (!int.TryParse(champs[1],out age) || age<0) {
//خطا را ثبت کنید
logs.WriteLine("La ligne n° [{0}] du fichier [{1}] a un âge [{2}] incorrect", numLigne, arguments[0], champs[1].Trim());
erreur = true;
}//اگر
// اگر خطایی وجود نداشته باشد، دادهها را در فایل دودویی بنویسید
if (!erreur) {
output.Write(nom);
output.Write(age);
}
// خط بعدی
}//در حالی که
}catch(Exception e){
Console.WriteLine("L'erreur suivante s'est produite : {0}", e.Message);
} finally {
// بستن فایلها
if(input!=null) input.Close();
if(output!=null) output.Close();
if(logs!=null) logs.Close();
}
}
}
}
بیایید نگاهی دقیقتر به عملیات مربوط به کلاس BinaryWriter بیندازیم:
- خط ۳۴: شیء BinaryWriter توسط عملیات باز میشود
output=new BinaryWriter(new FileStream(arguments[1],FileMode.Create,FileAccess.Write));
آرگومان سازنده باید یک استریم باشد. در اینجا، این استریمی است که از یک فایل (FileStream) ایجاد شده است، که برای آن فراهم میکنیم:
- (ادامه)
- نام
- عملی که باید انجام شود، در این مورد FileMode.Create برای ایجاد فایل
- نوع دسترسی، در اینجا FileAccess.Write برای دسترسی نوشتاری به فایل
- خطوط ۷۰–۷۳: عملیات نوشتن
کلاس BinaryWriter دارای متدهای مختلفی است که بازنویسی شدهاند، مانند Write، برای نوشتن انواع مختلف دادههای ساده
- خط ۸۱: عملیات بستن استریم
سه آرگومان برای متد Main به پروژه (از طریق ویژگیهای آن) [1] ارائه میشوند، و فایل متنی که باید پردازش شود در پوشه bin/Release [2] قرار داده میشود:
![]() |
با فایل زیر [personnes1.txt]:
نتایج اجرای برنامه به شرح زیر است:
![]() |
- در [1]، فایل باینری [personnes1.bin] و همچنین فایل لاگ [logs.txt] ایجاد شدند. فایل دوم محتوای زیر را دارد:
محتویات فایل باینری [personnes1.bin] توسط برنامه زیر ارائه خواهد شد. این برنامه همچنین سه آرگومان را میپذیرد:
//pg bin text logs syntax
//یک فایل باینری «bin» را میخواند و محتویات آن را در یک فایل متنی (text) ذخیره میکند
// فایل باینری دارای ساختاری متشکل از رشتهها و اعداد صحیح است
// فایل متنی شامل خطوطی به شکل نام : سن است
// logs یک فایل متنی حاوی لاگها است
بنابراین عملیات معکوس را انجام میدهیم. یک فایل باینری را میخوانیم تا یک فایل متنی ایجاد کنیم. اگر فایل متنی حاصل با فایل اصلی یکسان باشد، خواهیم دانست که تبدیل متن ← باینری ← متن با موفقیت انجام شده است. کد به شرح زیر است:
using System;
using System.IO;
// دستور: pg, bin, text, logs
//یک فایل باینری «bin» خوانده میشود و محتویات آن در یک فایل متنی («text») نوشته میشود
// فایل باینری ساختاری متشکل از رشتهها و اعداد صحیح دارد
// فایل متنی شامل خطوطی به شکل نام : سن است
// logs یک فایل متنی حاوی لاگها است
namespace Chap3 {
class Program2 {
static void Main(string[] arguments) {
//سه آرگومان لازم است
if (arguments.Length != 3) {
Console.WriteLine("syntaxe : pg binaire texte log");
Environment.Exit(1);
}//اگر
// متغیرها
string nom = null;
int age = 0;
int numPersonne = 1;
BinaryReader input = null;
StreamWriter output = null;
StreamWriter logs = null;
bool fini;
// خواندن فایل باینری – نوشتن فایل متنی
try {
// باز کردن فایل باینری برای خواندن
input = new BinaryReader(new FileStream(arguments[0], FileMode.Open, FileAccess.Read));
// باز کردن فایل متنی برای نوشتن
output = new StreamWriter(arguments[1]);
// باز کردن فایل لاگ برای نوشتن
logs = new StreamWriter(arguments[2]);
//پردازش فایل باینری
fini = false;
while (!fini) {
try {
// خواندن نام
nom = input.ReadString().Trim();
// خواندن سن
age = input.ReadInt32();
//نوشتن در فایل متنی
output.WriteLine(nom + ":" + age);
// فرد بعدی
numPersonne++;
} catch (EndOfStreamException) {
fini = true;
} catch (Exception e) {
logs.WriteLine("L'erreur suivante s'est produite à la lecture de la personne n° {0} : {1}", numPersonne, e.Message);
}
}//در حالی که
} catch (Exception e) {
Console.WriteLine("L'erreur suivante s'est produite : {0}", e.Message);
} finally {
//بستن فایلها
if (input != null)
input.Close();
if (output != null)
output.Close();
if (logs != null)
logs.Close();
}
}
}
}
بیایید نگاهی دقیقتر به عملیات مربوط به کلاس BinaryReader بیندازیم:
- خط ۳۰: شیء BinaryReader توسط عملیات باز میشود
input=new BinaryReader(new FileStream(arguments[0],FileMode.Open,FileAccess.Read));
آرگومان سازنده باید یک استریم باشد. در اینجا، این یک استریم ساختهشده از یک فایل (FileStream) است که برای آن فراهم میکنیم:
- (ادامه)
- نام
- عملی که باید انجام شود، در اینجا FileMode.Open برای باز کردن یک فایل موجود
- نوع دسترسی، در اینجا FileAccess.Read برای دسترسی خواندنی به فایل
- خطوط ۴۰، ۴۲: عملیات خواندن
کلاس BinaryReader دارای متدهای مختلفی ReadXX برای خواندن انواع مختلف دادههای ساده است
- خط ۶۰: عملیات بستن استریم
اگر دو برنامه را پشت سر هم اجرا کنیم، ابتدا personnes1.txt را به personnes1.bin و سپس personnes1.bin را به personnes2.txt2 تبدیل کنیم، نتایج زیر را به دست میآوریم:
![]() |
- به [1]؛ پروژه طوری پیکربندی شده است که برنامه دوم را اجرا کند
- در [2]، آرگومانهایی که به Main ارسال میشوند
- در [3]، فایلهای تولید شده توسط اجرای برنامه.
محتویات [personnes2.txt] به شرح زیر است:
5.7. بیانهای منظم
کلاس System.Text.RegularExpressions.Regex امکان استفاده از عبارتهای منظم را فراهم میکند. اینها امکان تست فرمت یک رشته کاراکتری را فراهم میکنند. برای مثال، میتوان بررسی کرد که آیا رشتهای که نشاندهنده یک تاریخ است، واقعاً در فرمت dd/mm/yy است. برای این کار، از یک الگو استفاده میشود و رشته با این الگو مقایسه میشود. بنابراین، در این مثال، d، m و y باید اعداد باشند. الگوی یک فرمت تاریخ معتبر بنابراین «\d\d/\d\d/\d\d» است، که در آن نماد \d نشاندهنده یک رقم است. نمادهایی که میتوان در یک الگو استفاده کرد به شرح زیر است:
توضیحات | |
کاراکتر زیر را بهعنوان یک کاراکتر ویژه یا صریح علامتگذاری کنید. برای مثال، «n» معادل کاراکتر «n» است. «\n» معادل کاراکتر خط جدید است. توالی «\\» معادل «\» است، در حالی که «\()» معادل «()» است. | |
مطابقت دارد با شروع ورودی. | |
نماینده پایان ورودی است. | |
با کاراکتر قبلی صفر یا چند بار مطابقت دارد. بنابراین، 'zo*' با 'z' یا 'zoo' مطابقت دارد. | |
با کاراکتر قبلی یک یا چند بار مطابقت دارد. بنابراین، «zo+» با «zoo» مطابقت دارد، اما با «z» مطابقت ندارد. | |
با کاراکتر قبلی صفر یا یک بار مطابقت دارد. برای مثال، «a?ve?» با «ve» در «lever» مطابقت دارد. | |
با هر کاراکتر واحدی مطابقت دارد، به جز کاراکتر خط جدید. | |
به دنبال modèle میگردد و تطبیق را ذخیره میکند. زیر رشتهی مطابقتیافته را میتوان با استفاده از آیتم [0]...[n] از مجموعه Matches حاصل استخراج کرد. برای یافتن مطابقتهایی که شامل کاراکترها در پرانتز ( ) هستند، از "(" یا ")" استفاده کنید. | |
مطابقت میکند با x یا y. برای مثال، «z|foot» با «z» یا «foot» مطابقت دارد. «(z|f)oo» با «zoo» یا «foo» مطابقت دارد. | |
n یک عدد صحیح غیرمنفی است. دقیقاً با n بار آن کاراکتر مطابقت دارد. برای مثال، «o{2}» با «o» در «Bob» مطابقت ندارد، اما با دو «o» اول در «fooooot» مطابقت دارد. | |
n یک عدد صحیح غیرمنفی است. این عبارت حداقل به n بار از این کاراکتر مطابقت دارد. برای مثال، «o{2,}» با «o» در «Bob» مطابقت ندارد، اما با تمام «o»ها در «fooooot» مطابقت دارد. «o{1,}» معادل «o+» و «o{0,}» معادل «o*» است. | |
m و n اعداد صحیح غیرمنفی هستند. با کاراکتر حداقل n و حداکثر m بار مطابقت میدهد. برای مثال، «o{1,3}» با سه «o» اول در «foooooot» مطابقت دارد و «o{0,1}» معادل «o؟» است. | |
مجموعه کاراکترها. یکی از کاراکترهای مشخصشده را مطابقت میدهد. برای مثال، «[abc]» با «a» در «plat» مطابقت دارد. | |
مجموعه کاراکتر منفی. با هر کاراکتری که در لیست ذکر نشده مطابقت دارد. برای مثال، "[^abc]" با "p" در "plat" مطابقت دارد. | |
محدوده کاراکتری. با هر کاراکتری که در محدوده مشخص شده باشد مطابقت دارد. برای مثال، "[a-z]" با هر کاراکتر الفبایی کوچک بین "a" و "z" مطابقت دارد. | |
محدوده کاراکتری منفی. با هر کاراکتری که در محدوده مشخصشده یافت نشود مطابقت دارد. برای مثال، «[^m-z]» با هر کاراکتری که بین «m» و «z» یافت نشود مطابقت دارد. | |
مطابقت میدهد با مرز کلمه، یعنی موقعیت بین یک کلمه و یک فاصله. برای مثال، "er\b" با "er" در "lever" مطابقت دارد، اما با "er" در "verbe" مطابقت ندارد. | |
یک مرز را مطابقت میدهد که نمایانگر یک کلمه نیست. «en*t\B» با «ent» در «bien entendu» مطابقت دارد. | |
با یک کاراکتر نمایانگر یک رقم مطابقت دارد. معادل [0-9] است. | |
مطابقت میدهد با یک کاراکتر که نمایانگر یک رقم نیست. معادل [^0-9] است. | |
مربوط به کاراکتر شکست صفحه است. | |
مطابق با کاراکتر پایان خط است. | |
مطابق با کاراکتر بازگشت به خانه است. | |
مطابقت دارد با هر فضای خالی، از جمله فاصله، تب، پایان صفحه و غیره. معادل "[ \f\n\r\t\v]". | |
هر کاراکتر غیرفاصلهای را مطابقت میدهد. معادل "[^ \f\n\r\t\v]". | |
با کاراکتر تب مطابقت دارد. | |
مطابقت میدهد با کاراکتر تب عمودی. | |
مطابقت دارد با هر کاراکتری که یک کلمه را نشان میدهد و شامل خط تیره (_) است. معادل "[A-Za-z0-9_]". | |
مطابقت دارد با هر کاراکتری که نمایانگر یک کلمه نباشد. معادل "[^A-Za-z0-9_]". | |
با num مطابقت دارد، که در آن num یک عدد صحیح مثبت است. به تطابقهای ذخیرهشده اشاره میکند. برای مثال، «(.)\1» با دو کاراکتر متوالی یکسان مطابقت دارد. | |
مطابق با n است، که در آن n یک مقدار فرار اکتال است. مقادیر فرار اکتال باید شامل ۱، ۲ یا ۳ رقم باشند. برای مثال، «\11» و «\011» هر دو معادل یک کاراکتر تب هستند. "\0011" معادل "\001" و "1" است. مقادیر فرار اکتال نباید از ۲۵۶ تجاوز کنند. اگر این اتفاق بیفتد، تنها دو رقم اول در عبارت در نظر گرفته میشوند. امکان استفاده از کدهای ASCII در عبارات باقاعده را فراهم میکند. | |
مطابق با n است، که در آن n یک مقدار فرار هگزادسیمال است. مقادیر فرار هگزادسیمال باید از دو رقم تشکیل شوند. به عنوان مثال، "\x41" معادل "A" است. "\x041" معادل "\x04" و "1" است. امکان استفاده از کدهای ASCII در عبارات منظم فراهم است. |
یک عنصر در یک الگو ممکن است یک یا چند بار ظاهر شود. بیایید به چند مثال مربوط به نماد \d که نماینده یک رقم است، نگاهی بیندازیم:
الگو | به معنای |
\d | یک رقم |
\d؟ | ۰ یا ۱ رقم |
* | صفر یا بیشتر رقم |
اعداد مثبت | ۱ یا چند رقم |
\d{2} | ۲ رقم |
\d{3,} | حداقل ۳ رقم |
\d{5,7} | بین ۵ تا ۷ رقم |
اکنون بیایید الگویی را در نظر بگیریم که قادر به توصیف قالب مورد انتظار برای یک رشته باشد:
رشته مقصد | الگو |
یک تاریخ در قالب dd/mm/yy | \d{2}/\d{2}/\d{2} |
یک زمان در قالب ساعت:دقیقه:ثانیه | \d{2}:\d{2}:\d{2} |
یک عدد صحیح بدون علامت | \d+ |
یک دنباله از فاصله، که ممکن است خالی باشد | \s* |
یک عدد صحیح بدون علامت که ممکن است قبل یا بعد از آن فضاها قرار داشته باشد | \s*\d+\s* |
یک عدد صحیح که ممکن است علامتدار باشد و قبل یا بعد از آن فضاها قرار گیرند | \s*[+|-]?\s*\d+\s* |
یک عدد حقیقی بدون علامت که ممکن است قبل یا بعد از آن فضا باشد | \s*\d+(.\d*)?\s* |
یک عدد حقیقی که ممکن است علامتدار باشد و قبل یا بعد از آن فاصلهها قرار گیرند | \s*[+|]?\s*\d+(.\d*)?\s* |
یک رشته حاوی کلمه juste | \bjuste\b |
میتوانید مشخص کنید که الگو را در کجای رشته جستجو کنید:
الگو | به معنی |
^pattern | الگو در ابتدای رشته آغاز میشود |
pattern$ | الگو رشته را پایان میدهد |
^الگو$ | الگو رشته را شروع و پایان میدهد |
الگو | الگو در هر جای رشته، از ابتدا جستجو میشود. |
رشته جستجو | الگو |
یک رشته که با علامت تعجب به پایان میرسد | !$ |
یک رشته که با نقطه پایان مییابد | \.$ |
یک رشته که با توالی // آغاز میشود | ^// |
یک رشته متشکل از یک کلمه واحد، که اختیاریاً قبل یا بعد از آن فاصلهها قرار میگیرند | ^[ \t*]+[ \t*]$ |
یک رشته متشکل از دو کلمه، که اختیاریاً میتواند قبل یا بعد از آن فضا باشد | ^\s*\w+\s*\w+\s*$ |
یک رشته حاوی کلمه secret | \bsecret\b |
زیرالگوها در یک الگو را میتوان «استخراج» کرد. بنابراین، نه تنها میتوانیم بررسی کنیم که آیا یک رشته با الگوی خاصی مطابقت دارد، بلکه میتوانیم عناصر مربوط به زیرالگوهای الگو که در کروشهها قرار گرفتهاند را از آن رشته استخراج کنیم. برای مثال، اگر در حال تحلیل رشتهای هستیم که تاریخ را به فرمت dd/mm/yy دارد و همچنین میخواهیم عناصر dd، mm و yy را از آن تاریخ استخراج کنیم، از الگوی (\d\d)/(\d\d)/(\d\d) استفاده خواهیم کرد.
5.7.1. بررسی اینکه آیا یک رشته با یک الگوی دادهشده مطابقت دارد
یک شیء Regex به صورت زیر ساخته میشود:
پس از ساخت الگوی عبارت منظم، میتوان آن را با رشتهها با استفاده از متد IsMatch مقایسه کرد:
در اینجا یک مثال آورده شده است:
using System;
using System.Text.RegularExpressions;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// یک الگوی عبارت منظم
string modèle1 = @"^\s*\d+\s*$";
Regex regex1 = new Regex(modèle1);
// مقایسهٔ یک نمونه با الگو
string exemplaire1 = " 123 ";
if (regex1.IsMatch(exemplaire1)) {
Console.WriteLine("[{0}] correspond au modèle [{1}]", exemplaire1, modèle1);
} else {
Console.WriteLine("[{0}] ne correspond pas au modèle [{1}]", exemplaire1, modèle1);
}//اگر
string exemplaire2 = " 123a ";
if (regex1.IsMatch(exemplaire2)) {
Console.WriteLine("[{0}] correspond au modèle [{1}]", exemplaire2, modèle1);
} else {
Console.WriteLine("[{0}] ne correspond pas au modèle [{1}]", exemplaire2, modèle1);
}//اگر
}
}
}
و نتایج اجرا:
5.7.2. یافتن تمام رخدادهای یک الگو در یک رشته
متد Matches برای بازیابی عناصری از یک رشته که با یک الگو مطابقت دارند، استفاده میشود:
کلاس MatchCollection دارای خاصیت Count است که تعداد عناصر مجموعه را نشان میدهد. اگر résultats یک نمونه از کلاس MatchCollection باشد، آنگاه results[i] عنصر i-ام این مجموعه است و از نوع Match میباشد. کلاس Match دارای خواص مختلفی است، از جمله موارد زیر:
- Value: مقدار شیء Match,، یعنی عنصری که با الگو مطابقت دارد
- Index: موقعیتی که عنصر در رشتهای که در حال پیمایش است، در آن یافت شده است
بیایید مثال زیر را در نظر بگیریم:
using System;
using System.Text.RegularExpressions;
namespace Chap3 {
class Program2 {
static void Main(string[] args) {
// چندین وقوع الگو در نمونه
string modèle2 = @"\d+";
Regex regex2 = new Regex(modèle2);
string exemplaire3 = " 123 456 789 ";
MatchCollection résultats = regex2.Matches(exemplaire3);
Console.WriteLine("Modèle=[{0}],exemplaire=[{1}]", modèle2, exemplaire3);
Console.WriteLine("Il y a {0} occurrences du modèle dans l'exemplaire ", résultats.Count);
for (int i = 0; i < résultats.Count; i++) {
Console.WriteLine("[{0}] trouvé en position {1}", résultats[i].Value, résultats[i].Index);
}//برای
}
}
}
- خط ۸: الگوی مورد جستجو یک دنباله از ارقام است
- خط ۱۰: رشتهای که این الگو در آن جستجو میشود
- خط ۱۱: تمام عناصر exemplaire3 که با الگوی modèle2 مطابقت دارند، بازیابی میشوند
- خطوط ۱۴–۱۶: اینها نمایش داده میشوند
خروجی اجرای برنامه به شرح زیر است:
5.7.3. استخراج بخشهای یک الگو
زیرمجموعههای یک الگو را میتوان «استخراج» کرد. بنابراین، نه تنها میتوانیم بررسی کنیم که یک رشته با الگوی خاصی مطابقت دارد، بلکه میتوانیم عناصر مربوط به زیرمجموعههای الگو که در کروشهها قرار گرفتهاند را از آن رشته استخراج کنیم. برای مثال، اگر در حال تحلیل رشتهای هستیم که تاریخ را به فرمت dd/mm/yy دارد و میخواهیم عناصر dd، mm و yy را از آن تاریخ استخراج کنیم، از الگوی (\d\d)/(\d\d)/(\d\d) استفاده خواهیم کرد.
بیایید به مثال زیر نگاه کنیم:
using System;
using System.Text.RegularExpressions;
namespace Chap3 {
class Program3 {
static void Main(string[] args) {
// استخراج عناصر در قالب
string modèle3 = @"(\d\d):(\d\d):(\d\d)";
Regex regex3 = new Regex(modèle3);
string exemplaire4 = "Il est 18:05:49";
//اعتبارسنجی قالب
Match résultat = regex3.Match(exemplaire4);
if (résultat.Success) {
// مثال با الگو مطابقت دارد
Console.WriteLine("L'exemplaire [{0}] correspond au modèle [{1}]",exemplaire4,modèle3);
//نمایش گروههای پرانتز
for (int i = 0; i < résultat.Groups.Count; i++) {
Console.WriteLine("groupes[{0}]=[{1}] trouvé en position {2}",i, résultat.Groups[i].Value,résultat.Groups[i].Index);
}//برای
} else {
// مثال با قالب مطابقت ندارد
Console.WriteLine("L'exemplaire[{0}] ne correspond pas au modèle [{1}]", exemplaire4, modèle3);
}
}
}
}
اجرای این برنامه نتایج زیر را تولید میکند:
ویژگی جدید در خطوط ۱۲–۱۹ یافت میشود:
- خط ۱۲: رشته exemplaire4 با قالب regex3 با استفاده از متد Match مقایسه میشود. این متد یک شیء Match را بازمیگرداند که قبلاً معرفی شده است. در اینجا از دو ویژگی جدید این کلاس استفاده میکنیم:
- Success (خط ۱۳): نشان میدهد که آیا تطابقی یافت شده است یا خیر
- Groups (خطوط 17، 18): یک مجموعه که
- Groups[0] با بخشی از رشته که با الگو مطابقت دارد، متناظر است
- Groups[i] (i ≥ 1) معادل مجموعهٔ i-ام کروشهها است
اگر résultat از نوع Match باشد، در این صورت résultats.Groups از نوع GroupCollection و résultats.Groups[i] از نوع Group است. کلاس Group دارای دو خاصیت است که ما در اینجا از آنها استفاده میکنیم:
- Value (خط ۱۸): مقدار شیء Group، که عنصری است که با محتوای یک پرانتز مطابقت دارد
- Index (خط ۱۸): موقعیتی که عنصر در رشته در حال تجزیه در آن یافت شده است
5.7.4. یک برنامه آموزشی
یافتن عبارت منظم (regular expression) که بررسی کند آیا یک رشته با الگوی خاصی مطابقت دارد یا خیر، گاهی اوقات میتواند یک چالش واقعی باشد. برنامه زیر به شما امکان میدهد تمرین کنید. این برنامه یک الگو و یک رشته را به عنوان ورودی میگیرد و مشخص میکند که آیا رشته با الگو مطابقت دارد یا خیر.
using System;
using System.Text.RegularExpressions;
namespace Chap3 {
class Program4 {
static void Main(string[] args) {
//دادهها
string modèle, chaine;
Regex regex = null;
MatchCollection résultats;
//از کاربر خواسته میشود قالبها و نمونههایی را که باید با این مورد مقایسه شوند، مشخص کند
while (true) {
//قالب درخواست میشود
Console.Write("Tapez le modèle à tester ou rien pour arrêter :");
modèle = Console.In.ReadLine();
//انجام شد؟
if (modèle.Trim() == "")
break;
//عبارت منظم ایجاد میشود
try {
regex = new Regex(modèle);
} catch (Exception ex) {
Console.WriteLine("Erreur : " + ex.Message);
continue;
}
//از کاربر میپرسیم که کدام نمونهها را باید با قالب مقایسه کنیم
while (true) {
Console.Write("Tapez la chaîne à comparer au modèle [{0}] ou rien pour arrêter :", modèle);
chaine = Console.ReadLine();
//انجام شد؟
if (chaine.Trim() == "")
break;
// انجام مقایسه
résultats = regex.Matches(chaine);
// موفق بود؟
if (résultats.Count == 0) {
Console.WriteLine("Je n'ai pas trouvé de correspondances");
continue;
}//اگر
// عناصر مطابقتیافته با الگو نمایش داده میشوند
for (int i = 0; i < résultats.Count; i++) {
Console.WriteLine("J'ai trouvé la correspondance [{0}] en position [{1}]", résultats[i].Value, résultats[i].Index);
// زیرعنصرها
if (résultats[i].Groups.Count != 1) {
for (int j = 1; j < résultats[i].Groups.Count; j++) {
Console.WriteLine("\tsous-élément [{0}] en position [{1}]", résultats[i].Groups[j].Value, résultats[i].Groups[j].Index);
}
}
}
}
}
}
}
}
در اینجا مثالی از اجرای برنامه آورده شده است:
5.7.5. متد Split
ما قبلاً با این روش در کلاس String مواجه شدهایم:
|
متد Split از کلاس Regex به ما امکان میدهد جداکننده را بر اساس یک قالب مشخص کنیم:
|
فرض کنید، برای مثال، یک فایل متنی شامل خطوطی به شکل field1, field2, …, fieldn باشد. فیلدها با ویرگول از هم جدا شدهاند، اما ممکن است قبل یا بعد از آن فاصلهها قرار داشته باشند. روش Split از کلاس string بنابراین مناسب نیست. روش RegEx راهحل را ارائه میدهد. اگر ligne خط خواندهشده باشد، میتوان فیلدها را با استفاده از
همانطور که در مثال زیر نشان داده شده است:
using System;
using System.Text.RegularExpressions;
namespace Chap3 {
class Program5 {
static void Main(string[] args) {
//یک ردیف
string ligne = "abc , def , ghi";
//یک قالب
Regex modèle = new Regex(@"\s*,\s*");
// تفکیک خط به فیلدها
string[] champs = modèle.Split(ligne);
//نمایش
for (int i = 0; i < champs.Length; i++) {
Console.WriteLine("champs[{0}]=[{1}]", i, champs[i]);
}
}
}
}
نتایج اجرا:
5.8. مثال کاربردی – V3
به سراغ برنامهای میرویم که در بخشهای ۳.۶ (نسخه ۱) و ۴.۱۰ (نسخه ۲) مورد بحث قرار گرفت.
در جدیدترین نسخه بررسیشده، محاسبه مالیات در کلاس انتزاعی AbstractImpot انجام شده است:
namespace Chap2 {
abstract class AbstractImpot : IImpot {
// محدودههای مالیاتی مورد نیاز برای محاسبه مالیات
// از یک منبع خارجی تأمین میشوند
protected TrancheImpot[] tranchesImpot;
//محاسبه مالیات
public int calculer(bool marié, int nbEnfants, int salaire) {
//محاسبه تعداد سهام
decimal nbParts;
if (marié) nbParts = (decimal)nbEnfants / 2 + 2;
else nbParts = (decimal)nbEnfants / 2 + 1;
if (nbEnfants >= 3) nbParts += 0.5M;
//محاسبه درآمد مشمول مالیات و ضریب خانوادگی
decimal revenu = 0.72M * salaire;
decimal QF = revenu / nbParts;
// محاسبه مالیات
tranchesImpot[tranchesImpot.Length - 1].Limite = QF + 1;
int i = 0;
while (QF > tranchesImpot[i].Limite) i++;
// نتیجه اظهارنامه
return (int)(revenu * tranchesImpot[i].CoeffR - nbParts * tranchesImpot[i].CoeffN);
}//محاسبه
}// محدوده
}
متد calculer در خط ۳۸ از آرایه tranchesImpot در خط ۳۵ استفاده میکند، آرایهای که توسط کلاس AbstractImpot مقداردهی اولیه نشده است. به همین دلیل این کلاس انتزاعی است و باید از آن ارثبری شود تا مفید باشد. این مقداردهی اولیه توسط کلاس مشتق HardwiredImpot انجام شده است:
using System;
namespace Chap2 {
class HardwiredImpot : AbstractImpot {
// جدولهای دادهای مورد نیاز برای محاسبه مالیات
decimal[] limites = { 4962M, 8382M, 14753M, 23888M, 38868M, 47932M, 0M };
decimal[] coeffR = { 0M, 0.068M, 0.191M, 0.283M, 0.374M, 0.426M, 0.481M };
decimal[] coeffN = { 0M, 291.09M, 1322.92M, 2668.39M, 4846.98M, 6883.66M, 9505.54M };
public HardwiredImpot() {
// ایجاد جدول ردههای مالیاتی
tranchesImpot = new TrancheImpot[limites.Length];
//پر کردن
for (int i = 0; i < tranchesImpot.Length; i++) {
tranchesImpot[i] = new TrancheImpot { Limite = limites[i], CoeffR = coeffR[i], CoeffN = coeffN[i] };
}
}
}//کلاس
}// فضای نام
در مثال بالا، دادههای مورد نیاز برای محاسبه مالیات بهصورت سختکد در کلاس قرار داده شده بود. نسخه جدید مثال آن را در یک فایل متنی قرار میدهد:
4962:0:0
8382:0,068:291,09
14753:0,191:1322,92
23888:0,283:2668,39
38868:0,374:4846,98
47932:0,426:6883,66
0:0,481:9505,54
از آنجا که پردازش این فایل ممکن است به خطاها (exceptions) منجر شود، ما یک کلاس ویژه برای رسیدگی به آنها ایجاد میکنیم:
using System;
namespace Chap3 {
class FileImpotException : Exception {
// کدهای خطا
[Flags]
public enum CodeErreurs { Acces = 1, Ligne = 2, Champ1 = 4, Champ2 = 8, Champ3 = 16 };
// کد خطا
public CodeErreurs Code { get; set; }
// سازندهها
public FileImpotException() {
}
public FileImpotException(string message)
: base(message) {
}
public FileImpotException(string message, Exception e)
: base(message,e) {
}
}
}
- خط ۴: کلاس FileImpotException از کلاس Exception ارث میبرد. این کلاس برای ثبت هرگونه خطایی که هنگام پردازش فایل داده متنی رخ میدهد، استفاده خواهد شد.
- خط ۷: یک شمارشگر (enumeration) که نمایانگر کدهای خطا است:
- Acces: خطا در دسترسی به فایل داده متنی
- Ligne: ردیف شامل سه فیلد مورد انتظار نیست
- Champ1: فیلد شماره ۱ نادرست است
- Champ2: فیلد شمارهٔ ۲ نادرست است
- Champ3: فیلد شماره ۳ نادرست است
برخی از این خطاها ممکن است به صورت ترکیبی رخ دهند (Champ1, Champ2, Champ3). در نتیجه، شمارهگذاری CodeErreurs با ویژگی [Flags] نشانهگذاری شده است، که نشان میدهد مقادیر مختلف این شمارهگذاری باید توانهای ۲ باشند. بنابراین، خطا در فیلدهای ۱ و ۲ منجر به کد خطای Champ1 | Champ2 خواهد شد.
- خط ۱۰: ویژگی خودکار Code کد خطا را ذخیره خواهد کرد.
- خط ۱۵: یک سازنده که امکان ایجاد یک شیء FileImpotException را با ارسال یک پیام خطا بهعنوان پارامتر فراهم میکند.
- خط ۱۸: یک سازنده که امکان ایجاد یک شیء FileImpotException را با ارسال یک پیام خطا و استثنایی که باعث ایجاد خطا شده است بهعنوان پارامتر فراهم میکند.
کلاسی که آرایه tranchesImpot از کلاس AbstractImpot را مقداردهی اولیه میکند اکنون به شرح زیر است:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
namespace Chap3 {
class FileImpot : AbstractImpot {
public FileImpot(string fileName) {
// دادهها
List<TrancheImpot> listTranchesImpot = new List<TrancheImpot>();
int numLigne = 1;
// استثناء
FileImpotException fe = null;
// خواندن محتویات فایل fileName، خط به خط
Regex pattern = new Regex(@"s*:\s*");
// در ابتدا هیچ خطایی وجود ندارد
FileImpotException.CodeErreurs code = 0;
try {
using (StreamReader input = new StreamReader(fileName)) {
while (!input.EndOfStream && code == 0) {
// خط فعلی
string ligne = input.ReadLine().Trim();
// خطوط خالی نادیده گرفته میشوند
if (ligne == "") continue;
// خط به سه فیلد تقسیم شده که با جداکننده زیر از هم جدا شدهاند:
string[] champsLigne = pattern.Split(ligne);
//آیا سه فیلد وجود دارد؟
if (champsLigne.Length != 3) {
code = FileImpotException.CodeErreurs.Ligne;
}
//تبدیلهای سه فیلد
decimal limite = 0, coeffR = 0, coeffN = 0;
if (code == 0) {
if (!Decimal.TryParse(champsLigne[0], out limite)) code = FileImpotException.CodeErreurs.Champ1;
if (!Decimal.TryParse(champsLigne[1], out coeffR)) code |= FileImpotException.CodeErreurs.Champ2;
if (!Decimal.TryParse(champsLigne[2], out coeffN)) code |= FileImpotException.CodeErreurs.Champ3; ;
}
// خطا؟
if (code != 0) {
//خطا ثبت شده است
fe = new FileImpotException(String.Format("Ligne n° {0} incorrecte", numLigne)) { Code = code };
} else {
// محدوده مالیاتی جدید ثبت میشود
listTranchesImpot.Add(new TrancheImpot() { Limite = limite, CoeffR = coeffR, CoeffN = coeffN });
// خط بعدی
numLigne++;
}
}
}
//انتقال لیست listImpot به آرایه tranchesImpot
if (code == 0) {
//انتقال لیست listImpot به آرایه tranchesImpot
tranchesImpot = listTranchesImpot.ToArray();
}
} catch (Exception e) {
//خطا ثبت شد
fe= new FileImpotException(String.Format("Erreur lors de la lecture du fichier {0}", fileName), e) { Code = FileImpotException.CodeErreurs.Acces };
}
// آیا باید خطا گزارش شود؟
if (fe != null) throw fe;
}
}
}
- خط ۷: کلاس FileImpot از کلاس AbstractImpot ارث میبرد، درست همانطور که کلاس HardwiredImpot در نسخه ۲ این کار را انجام داد.
- خط ۹: سازنده کلاس FileImpot مسئول مقداردهی اولیه فیلد trancheImpot در کلاس پایه خود AbstractImpot است. این سازنده نام فایل متنی حاوی دادهها را بهعنوان پارامتر میپذیرد.
- خط ۱۱: فیلد tranchesImpot از کلاس پایه AbstractImpot یک آرایه است که باید با دادههای فایل filename که بهعنوان پارامتر ارسال شده، پر شود. خواندن یک فایل متنی یک فرآیند ترتیبی است. تعداد خطوط تنها پس از خواندن کامل فایل مشخص میشود. بنابراین، آرایه tranchesImpot را نمیتوان از پیش تخصیص داد. دادهها بهطور موقت در لیست عمومی listTranchesImpot ذخیره خواهند شد.
توجه داشته باشید که نوع TrancheImpot یک ساختار است:
namespace Chap3 {
//یک رده مالیاتی
struct TrancheImpot {
public decimal Limite { get; set; }
public decimal CoeffR { get; set; }
public decimal CoeffN { get; set; }
}
}
- خط ۱۴: fe، از نوع FileImpotException، برای محصور کردن هرگونه خطایی که ممکن است هنگام پردازش فایل متنی رخ دهد، استفاده میشود.
- خط 16: عبارت منظم برای جداکنندهٔ فیلد در یک خط champ1:champ2:champ3 از فایل متنی. فیلدها با کاراکتر : از هم جدا میشوند، که میتواند قبل و بعد از آن هر تعداد فاصله باشد.
- خط ۱۸: کد خطا در صورت بروز خطا
- خط ۲۰: پردازش فایل متنی با استفاده از StreamReader
- خط ۲۱: حلقه تا زمانی که یک خط برای خواندن باقی مانده باشد و هیچ خطایی رخ نداده باشد، ادامه مییابد.
- خط ۲۷: خط خواندهشده با استفاده از عبارت منظم موجود در خط ۱۶ به فیلدها تقسیم میشود
- خطوط ۲۹–۳۱: بررسی اینکه آیا خط واقعاً دارای سه فیلد است – ثبت هرگونه خطا
- خطوط ۳۳–۳۸: سه رشته به سه عدد اعشاری تبدیل میشوند – هرگونه خطا ثبت میشود
- خطوط ۴۰–۴۳: اگر خطایی رخ داده باشد، یک استثنا از نوع FileImpotException ایجاد میشود.
- خطوط 44–47: اگر خطایی رخ نداده باشد، پس از ذخیره دادههای خط فعلی، به خواندن خط بعدی فایل متنی ادامه میدهیم.
- خطوط ۵۲–۵۵: با خروج از حلقه while، دادههای لیست عمومی listTranchesImpot در آرایه tranchesImpot از کلاس پایه AbstractImpot کپی میشود. شایان ذکر است که این همان هدف مورد نظر سازنده بود.
- خطوط ۵۶–۵۹: رسیدگی به یک استثناء احتمالی. این در یک شیء از نوع FileImpotException محصور شده است.
- خط ۶۱: اگر استثنای fe از خط ۱۸ مقداردهی اولیه شده باشد، آنگاه پرتاب میشود.
پروژه کامل C# به شرح زیر است:
![]() |
- در [1]: کل پروژه
- در [2,3]: ویژگیهای فایل [DataImpot.txt] [2]. ویژگی [Copy to Output Directory] [3] روی 'always' تنظیم شده است. این بدان معناست که فایل [DataImpot.txt] هر بار که پروژه اجرا میشود، به پوشه bin/Release (حالت انتشار) یا bin/Debug (حالت اشکالزدایی) کپی خواهد شد. این همان جایی است که فایل اجرایی آن را جستجو میکند.
- در [4]: همین امر در مورد فایل [DataImpotInvalide.txt] نیز صدق میکند.
محتویات [DataImpot.txt] به شرح زیر است:
4962:0:0
8382:0,068:291,09
14753:0,191:1322,92
23888:0,283:2668,39
38868:0,374:4846,98
47932:0,426:6883,66
0:0,481:9505,54
محتویات [DataImpotInvalide.txt] به شرح زیر است:
برنامه آزمون [Program.cs] بدون تغییر باقی مانده است: این همان برنامه نسخه ۲، بند ۴.۱۰ است، با تفاوت زیر:
using System;
namespace Chap3 {
class Program {
static void Main() {
...
//ایجاد یک شیء IImpot
IImpot impot = null;
try {
// ایجاد یک شیء IImpot
impot = new FileImpot("DataImpot.txt");
} catch (FileImpotException e) {
//نمایش خطا
string msg = e.InnerException == null ? null : String.Format(", Exception d'origine : {0}", e.InnerException.Message);
Console.WriteLine("L'erreur suivante s'est produite : [Code={0},Message={1}{2}]", e.Code, e.Message, msg == null ? "" : msg);
//پایان برنامه
Environment.Exit(1);
}
//حلقه بینهایت
while (true) {
...
}//در حالی که
}
}
}
- خط ۸: شیء impot از نوع تعریفشده توسط رابط IImpot
- خط ۱۱: نمونهسازی شی impot با یک شی از نوع FileImpot. این ممکن است یک استثنا ایجاد کند که توسط بلوکهای try/catch در خطوط ۹، ۱۲ و ۱۸ مدیریت میشود.
در اینجا چند مثال از اجرا آورده شده است:
با فایل [DataImpot.txt]
با یک فایل [xx] که وجود ندارد
با فایل [DataImpotInvalide.txt]






























