ویژگی های مخصوص زبان #C

کلاس های جزئی (Partial Classes)

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

File1.cs                                                                                                                

public  partial class MyClass                                                                         {                                                                                           

                public  void  MyMethod1()                                                              

{                                                                                                                  

//manually written code                                                                      }                                                                                                                  

}                                                                                                                             

File2.cs

public  partial class MyClass       

{

public  void  MyMethod2()

{

//automatically  generated code

}

}

Generics

Generics یا انواع  پارامتری شده (Parameterized types) یا چند ریختی پارامتری (Parametric polymorphism) یکی از ویژگی های چهارچوبNet.است که توسط #C پشتیبانی می شود. بر خلاف الگو (template)های ++ C ، انواع پارامتری چهارچوب  Net. به جای این که توسط کامپایلر مقداردهی اولیه شوند، فقط در زمان اجرا مقداردهی می شوند. یعنی این انواع می توانند در هر دو زبان استفاده شوند، در حالی که الگوهای ++C چنین قابلیتی ندارند. این انواع پارامتری شده برخی ویژگی هایی را که مستقیما توسط الگوهای ++ C پشتیبانی نمی شود پشتیبانی می کنند از جمله محدودیت های انواع داده که به متغیرهای generic با استفاده از واسط (Interface)ها اعمال می شود. از جهت دیگر، ++C متغیرهای بدون انواع عمومی را پشتیبانی نمی کند. بر خلاف generics  در زبان جاوا ، generics در چهارچوب Net. از روش جسمیت دادن یا reification برای ایجاد اشیایی که دارای انواع پارامتری شده در CLI هستند استفاده می کند که این روند اجازه ی بهینه سازی و نگهداری مطلوب اطلاعات انواع داده ای را به برنامه نویس می دهد .

 

کلاس های ایستا   (Static Classes)

کلاس های ایستا ، کلاس هایی هستند که نمی توان از آن ها به ارث برد یا شی ایجاد کرد و فقط دارای اعضای ایستا هستند. هدف ایجاد این کلاس ها بسیار شبیه واحد (module) هایی است که در بسیاری از زبان های ساخت یافته وجود دارند.

 

ایجاد وظیفه ی کد (Generator   functionality)

چهارچوب Net. به #C اجازه می دهد تا با استفاده از عبارت کلیدی yield return  ، ایجاد وظیفه ی کد را فراهم کند . این عبارت کلیدی شبیه کلمه ی کلیدی yield در زبان  Python  است .

//Method that takes an iterable input (possibly an array)

//and returns all even numbers

public  static IEnumerable   GetEven (IEnumerable  numbers)

{

    foreach(int i in numbers )

{

                if(i % 2 == 0)

                                 yield  return  i;

}            

}

 هم چنین عبارت دیگری به شکل yield break وجود دارد که  در آن کنترل به صورت غیر منتظره به جزئی که اشاره گر را فراخوانده باز می گردد . به طور کلی همیشه یک عبارت  yield break  در انتهای هر متد مولد کدی وجود دارد.

نمایندگی های بی نام  (Anonymous  delegates)

پیش از معرفی توابع lambda ، ویژگی به نام anonymous delegate  به #C افزوده شده بود. این ویژگی باعث فراهم آمدن کارکردی به نام closure-like شده است. کدی که درون یک anonymous delegate قرار دارد به متغیرهای محلی، پارامترهای توابع و اعضای کلاس در حوزه ی نمایندگی دسترسی کامل دارد. فقط به پارامترهایی که با کلمات کلیدی  out , ref مشخص شده اند دسترسی ندارد. به عنوان مثال،

int   SumArrayElements(int[]  array)

{

int  sum  = 0;

Array.ForEach(array,  delegate(int  x) {sum  +=  x;} );

return  sum ;

}

بر خلاف پیاده سازی های closure-like ، هر متغیر یک anonymous  delegate ، به فضای حافظه ای که برای هر متغیر مرتبط با تابع در نظر گرفته شده دسترسی دارد . بحث در مورد anonymous delegate   بسیار گسترده است و در این جا مجال ذکر تمام آن نیست .

تعیین سطح دسترسی به متغیرها (The accessibility  of  property accessor)

برای توضیح این ویژگی به ذکر یک مثال اکتفا می کنیم :

string  status  = string.Empty;

public  string  Status

{

 get  {return  status;}                      //anyone can get the value of this property

protected  set  {status  =  value;}               //but only derived classes can change it

}

نوع داده تهی (Nullable  type)

نوع داده تهی (که با یک علامت سوال مشخص می شود مانند ;int?  i = null) مقدار null  را به مجموعه ی مقادیری که هر متغیر می تواند اختیار کند ، اضافه می کند. این ویژگی روابط متقابل با پایگاه داده ی SQL را بهبود بخشیده است ، چرا که SQL می تواند با توجه به انواع داده ی اولیه #C دارای ستون خالی باشد . مثلا ستون  INTEGER NULL مستقیما به صورت? int در #C ترجمه می شود . لازم به ذکر است که هنگامی که یک متغیر تهی مقدار null  می گیرد ، در حقیقت ارجاعی به مقدار null  نیست ، بلکه متغیری از نوع  Nullable و دارای ویژگی HasValue است که با مقدار false  تنظیم می شود . هنگامی که این متغیر محصور یا box  می شود، تنها متغیر Nullable محصور می شود و نه مقدار ذخیره شده در آن. بنابراین نتیجه همیشه غیر تهی خواهد بود  حتی برای مقادیر null . برای امتحان از قطعه کد زیر استفاده کنید :

int? i = null;

object  o  =  i ;

if(o  ==  null )

                System.Console.WriteLine("Correct  Behaviour");

else

                System.Console.WriteLine("Incorrect  Behaviour");

وقتی متغیری از نوع NULL در یک شی محصور می شود مقداری که در بخش متغیر NULL  وجود دارد، رها می شود. بنابراین مقدار null  و ارجاع null به صورت یکسان در نظر گرفته می شود . ماهیت این ویژگی موجب ایجاد برخی اشکالات شد، زیرا رفع این اشکال نیازمند تغییرات اساسی در هسته ی CLR  بود که نه تنها چهارچوب Net. بلکه تکنولوژی های وابسته به آن (نظیر C#, VB,SQL Server, Visual Studio ) را تحت تاثیر قرار می داد .

عملگر تشخیص تهی بودن  (Null - Coalesce operator)

عملگر ?? ، عملگر تشخیص تهی بودن نامیده می شود و برای تشخیص یک مقدار پایه بین متغیرهای null و ارجاع ها به کار می رود .

عماکرد آن به این گونه است که اگر عملوند سمت چپ null نباشد ، آن را برمی گرداند و در غیر این صورت عملوند سمت راست را بر می گرداند .

; object nullObj = null

; ()object obj = new Object

return nullObj ?? obj;     //returns obj

استفاده ابتدایی این عملگر برای نسبت دادن یک مقدار nullable به یک متغیر non-nullable به کمک کد ساده بود:

 

; int? i = null

int j = i ?? 0;    //if i is not null, initialize j to. Else(if i is null), initialize j to 0

زبان متحد پرس و جو  Language - Integrated Query (LINQ)

LINQ زبان پرس و جوی جدید ، توسعه پذیر و همه جانبه ی مایکروسافت است که برای بسیاری از انواع منابع داده ای مورد استفاده قرار می گیرد (از جمله collection  های ساده XML ، پایگاه داده و ...)که با بسیاری از فضای زبان#C هماهنگ و یک پارچه است . syntax آن قدری متفاوت است، اما به عنوان مثال از SQL داریم:

int[] array = {1, 5, 2, 10, 7};

IEnumerable  query  = from  x  in  array

                                                where  x % 2 == 1

                                                where  x  descending

select  x * x;

//Result : 49, 25, 1

در راستای پیاده سازی LINQ  گستره ی وسیعی از متدهای جدید به بسیاری از collection  ها توسط کلاس System.Linq.Enumerable افزوده شد. عبارات زبان LINQ پیش از کامپایل ترجمه می شوند تا بتوانند از این متدها استفاده کنند. اما ممکن است این توابع مستقیما در دسترس قرار بگیرند که در این صورت قوی تر از شرایط عادی عمل خواهند کرد. چنین عملکردی موجب استفاده ی بیشتر از توابع lambda می شود که در ادامه در مورد آن بحث خواهیم کرد. مثال زیر از نظر عملکرد کاملا شبیه مثال بالاست:

 IEnumerable query = array.Where(x  =>  x % 2 == 1).OrderByDescending(x => x).Select(x  => x * x);

//Result: 49, 25, 1

 

ایجاد کردن اشیا (Object Initializers )

قطعه کد

 ; ()Customer c =new Customer

;" c.Name = "James

می تواند به صورت زیر نوشته شود:

Customer  c = new Customer  {Name = "James" };

ایجاد کردن Collection  ها (Collection Initializers)

قطعه کد :

MyList list =new MyList();

list.Add(1);

list.Add(2);

می تواند به صورت :

MyList list =new MyList {1,2};

نوشته شود. با این فرض که کلاس MyList ، اینترفیس System.Collection.IEnumerable را پیاده سازی کند و دارای یک متد عممومی به نام Add  باشد.

 

انواع بی نام  (Anonymous types )

به مثال زیر توجه کنید :

var  x = new {FirstName = "James", LastName  =  "Frank"};

 

استنتاج نوع متغیر محلی  (Local variable type inference)

استنتاج نوع متغیر محلی به صورت:

var  x =new  Dictionary >();

 با قطعه کد زیر قابل تعویض است:

Dictionary >  x  =  new Dictionary >();

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

عبارات ( Lambda  (Lambda Expressions

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

listOfFoo.Where(delegate(Foo x)  {return  x.Size>10; } )

 

listOfFoo.Where(x  =>  x.size  > 10);

 در مثال های بالا عبارات Lambda تنها راهی برای کم حجم کردن عبارات ورودی و مقادیر خروجی توابع هستند. به هر حال با توجه به متن کد، استفاده از این عبارات متفاوت خواهد بود. مثلا کامپایلر #C می تواند این عبارات را به کدهای  AST تبدیل کند تا در زمان اجرا پردازش شوند. در مثال بالا  اگر listOfFoo یک collection ساده نباشد ، بلکه کلاس پوشاننده ی جدول یک پایگاه داده باشد می تواند از این روش برای ترجمه ی عبارت Lambda به عبارت معادل در SQL جهت اجرای بهینه استفاده کند. از جهت دیگر عبارت Lambda کاملا شبیه کد معمولی می باشد، بنابراین طریقه ی استفاده ی آن در زمان اجرا برای استفاده کننده کاملا مشخص است.

 

 درخت های عبارت (Expression trees)

عباراتی نظیر x<=y  ، a = b + c یا حتی توابع Lambda و دیگر اشکال پیچیده ی کد می توانند با استفاده از درخت های عبارت به صورت دینامیک اجرا شوند. بخش بزرگی از این راهکار توسط متدهای ایستای کلاس System.Expressions.Expression مهیا می شود. هم چنین کلاس های متفاوتی در این namespace وجود دارد که حاوی عبارات جزئی و کلی هستند و توسط همان متدهای ایستا به عنوان اشیا نرم افزاری ایجاد شده اند. این اشیا شامل Binary Expression   نظیر x<= y ، lambda expression  و ... می باشند. استفاده از این اشیا ابزار بسیار قدرتمندی در هنگام رقابت بر سر کد نویسی و اشکال زدایی (debug) آن به شمار می رود.

متدهای توسعه  (Extension  Methods )

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

public  static  class StringExtensions

{

                public  static  string  Left (this string s, int n )

{

                return s.Substring(0,n);

}

}

string  s = "foo";

s.Left(3);              //same  as  StringExtensions.Left(s,3);

متدهای جزئی  (Partial  methods)

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

تنظیم اتوماتیک خاصیت ها  (Automatic  Property   Set)

کامپایلر برای خاصیت (property) های هر کلاس متدهایی را برای بازگرداندن و تنظیم مقدار آنها ارائه می کند. به صورت زیر:

public  string Name  {get ; private set;}

عضو انتخابی دینامیک  (Dynamic  member  lookup )

نوع داده ی جدیدی به نام dynamic  در سیستم نوع داده ی #C معرفی شد که در حقیقت شبیه نوع داده های معمولی است. این نوع داده به عنوان System.Object تلقی می شود. به علاوه این که هر گونه عملیات بر روی متغیرهایی که از این نوع اعلان می شوند از جمله دسترسی، ورودی یا خروجی توابع، انجام عملیات منطقی و... بدون بررسی انجام می شود و تحلیل وضعیت تا زمان اجرا به تعویق می افتد. برای مثال:

//returns the value of length property or field of any object

int GetLength(dynamic  obj)

{

   return  obj.Length;

}

GetLength("Hello,World"); // a string has a length property

GetLength(new int[] {1,2,3}); //and so does on array

GetLength(42); // but not an integer- an exception will be thrown here at run- time

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

void Print (dynamic obj)

{

                System.Console.WriteLine(obj);

}

Print(123);

Print("abc");

Dynamic lookup  با سه مکانیزم مختلف قابل اجراست:

Com IDispatch برای اشیای Com ، واسط IDynamic Object برای اشیایی که این واسط را پیاده سازی می کنند و روش Reflection  برای تمام اشیا دیگر. بنابراین هر کلاسی که در #C تعریف می شود می تواند از فراخوانی دینامیک اشیایی که در آن ایجاد می شوند توسط پیاده سازی IDynamic object جلوگیری کند. در مورد متد دینامیک و فراخوانی های با اندیس، پردازش متناسب با نوع فراخوانی در زمان اجرا صورت می گیرد. البته با توجه به نوع حقیقی مقادیری که به عنوان آرگومان رد می شوند این پردازش صورت می گیرد. در غیر این صورت با توجه به قوانین پردازش معمولی #C پردازش خواهند شد. علاوه بر این، در مواردی که دریافت کننده ی فراخوانی دینامیک، خود دینامیک نباشد، در هنگام پردازش تنها متدهایی که چگونگی کامپایل شدن آنها صریح است در نظر گرفته می شوند. به عنوان مثال:

class Base

{

                void Foo(double x);

}

class Derived: Base

{

                void Foo(int x );

}

dynamic x = 123;

Base b = new Derived ();

b.Foo(x);    // picks Base.Foo(double ) becomes b is of type Base and Derived.Foo(int) is not exposed

dynamic b1 = b;

b1.Foo(x);  //picks Derived.Foo(int)

نوع داده ی هر مقداری که از دسترسی اعضای دینامیک به دست آید، خود dynamic است. متغیرهایی که از نوع dynamic تعریف می شوند، قابل تبدیل به هر نوع دیگری هستند. در کد چند مثال قبل این قابلیت تبدیل به تابع GetLength اجازه می دهد که با مقدار بازگشتی از فراخوانی Length به عنوان یک عدد صحیح برخورد کند؛ بدون هیچ عملیات اضافه ای. و البته در زمان اجرا مقدار حقیقی به نوع داده ی خواسته شده تبدیل خواهد شد .

Covariant and contravariant generic type parameters

اینترفیس های generic  و نمایندگی ها(delegates)  می توانند نوع داه ی  پارامترهایشان را به صورت covariant و یا contravariant و با استفاده از کلمات کلیدی in , out به کار بگیرند. سپس این تعاریف برای تبدیل انواع داده دارای اهمیت خواهند بود، چه به صوت الزامی و چه اختیاری، چه در زمان اجرا و چه در زمان کامپایل. به عنوان مثال واسط IEnumerable که تعریف آن موجود می باشد را می توان به صورت زیر دوباره تعریف کرد:

interface IEnumerable

{

                IEnumerable      GetEnumerable();

}

بنابراین هر کلاسی که IEnumerable را با استفاده از Derived پیاده سازی کند ، با IEnumerable (که در آن Base می تواند هر کلاس یا واسطی باشد که Derived  به صورت مستقیم یا غیر مستقیم از آن مشتق شده ) نیز سازگار است . در عمل نمی توان قطعه کدی به صورت زیر داشت :

void PrintAll(IEnumerable );

 

/ 1 نظر / 37 بازدید
xsidos

vaghean matlabe jaleB bo0d...har koodoom az in vizhegi ha ye donya harf vase goftan daran ama in maghale ba eshareE kootah ama kArA bekhooB zabane C# o tashrih karde...ba tashakor az matlabe khoobetoon[گل]