PDA

View Full Version : سوال: Reflection به زبان ساده



Mostafa_Dindar
یک شنبه 02 اسفند 1388, 01:11 صبح
سلام .

از دوستان كسي ميتونه به زبان ساده كمي در مورد Reflection توضيح بده .

ممنون

r00tkit
یک شنبه 02 اسفند 1388, 01:54 صبح
سلام


One very powerful feature of .NET is that it allows you to write code to access an application's metadata through a process known as reflection. Put simply, reflection is the ability to discover type information at run time


reflection به زبان ساده یعنی توانایی دست رسی به metadata ای اسمبلی در زمان اجرا(run time) و پرس وجو از ان





using System;
using System.Reflection;
class TypeObjectFromInstanceApp {
public static void Main(string[] args) { int i = 6; Type t = i.GetType(); Console.WriteLine(t.Name); } }

Mostafa_Dindar
یک شنبه 02 اسفند 1388, 10:55 صبح
Investigating and exploring makes everything perfect. كمي تحقيق و جستجو كردم . اميدوارم بدرد دوستان هم بخوره .


در طی این مقاله شما را با یکی از تکنیکهای جالب و بسیار کارا در محیط .NET به نام Reflection آشنا می کنیم. با استفاده از این ویژگی شما قادر خواهید بود اطلاعات مربوط به یک شیء یا کلاس را در زمان اجرا (Runtime) بدست آورید. این اطلاعات شامل جزئیات دقیق خصوصیات (Properties) و متدهایی که در آن شیء یا کلاس وجود دارند، می باشد. علاوه بر اینها، اطلاعات دیگری نیز برای شما قابل دسترس خواهد بود که در ادامه به توضیح آنها خواهیم پرداخت. برای استفاده از این تکنیک بایستی از فضای نام System.Reflection استفاده کنید. برای سهولت کار می توانید این فضای نام را در قسمت بالای فایل کد خود using کنید (Imports در VB.NET).



برای اینکه اهمیت استفاده از Reflection برای شما بیشتر مشخص گردد، مثال زیر را در نظر بگیرید:



public void DisplayType(object obj)

{

Console.Write("The type of 'obj' is Unknown!");

}



فرض کنید که در زمان اجرا، اشیای متفاوتی به متد فوق ارسال می شوند؛ و شما نیز می خواهید بسته به نوع شیئی که به این متد ارسال شده است، کار خاصی را انجام دهید. برای اینکار شما باید ابتدا نوع شیء obj را تشخیص دهید. برای تشخیص نوع این شیء روشهای متفاوتی وجود دارند. یکی از این روشها استفاده از عملگر is است. به مثال زیر توجه کنید:



public void DisplayType(object obj)

{

if (obj is Button)

Console.Write("The type of 'obj' is Button.");

else if (obj is TextBox)

Console.Write("The type of 'obj' is TextBox.");

}



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



public void DisplayType(object obj)

{

Type t = obj.GetType();

if (t == typeof(Button))

Console.Write("The type of 'obj' is Button.");

else if (t == typeof(TextBox))

Console.Write("The type of 'obj' is TextBox.");

}



در مثال فوق، از عملگر typeof برای شناسایی نوع یک کلاس استفاده شده است. متد GetType() نیز متدی است که از کلاس object به ارث رسیده و در تمام اشیا قابل فراخوانی است. این متد یک خروجی از جنس Type دارد. دقت داشته باشید که عملگر typeof نام یک کلاس را مانند یک ورودی دریافت کرده و نوع آن را بر می گرداند ولی متد GetType() از طریق یک شیء فراخوانی شده و نوع آن را بر می گرداند. بنابراین در مثال زیر خطوط 2 و 3 معادل یکدیگرند:



1: Form f = new Form();

2: Type t1 = typeof(Form);

3: Type t2 = f.GetType();



برای شروع کار با Reflection باید نوع شیء مورد نظر را توسط متد GetType() در یک متغیر از جنس Type قرار داد. بنابراین جنس اشیاء در .NET خود نوعی شیء است! حال نگاهی دقیقتر به کلاس Type می اندازیم. Typeکلاسی است که در نمونه های آن می توان اطلاعات ساختاری مربوط به کلاسهای دیگر را ذخیره کرد. این اطلاعات ساختاری شامل جزئیات دقیق هر کلاس مانند: Propertyها، Methodها، Eventها، Constructorها، Indexerها و دیگر خصوصیات آن می باشد. اصطلاح Reflection نیز از اینجا ناشی می شود که یک شیء Type می تواند خصوصیات و اطلاعات جزئی هر کلاس را در زمان اجرا به برنامه نویس انعکاس دهد. شیء Type حاوی خصوصیات و متد های فراوانی است که ما در اینجا به مهمترین آنها می پردازیم:



* BaseType: نوع کلاس پدر یک کلاس را مشخص می کند (فقط یک سطح بالاتر)
* :FullName نام یک کلاس را به همراه فضای نام کامل آن مشخص می کند
* :GetConstructors سازنده های یک کلاس را بر می گرداند
* :GetEvents رویدادهای یک کلاس را بر می گرداند
* :GetFields متغیر هایی را که در سطح کلاس تعریف شده اند را بر می گرداند
* :GetInterfaces رابط هایی که یک کلاس از آنها پشتیبانی می کند را بر می گرداند
* :GetMethods متدهای یک کلاس را بر می گرداند
* :GetProperties خصوصیات یک کلاس را بر می گرداند
* :Name فقط نام یک کلاس را مشخص می کند
* :Namespace فقط فضای نام یک کلاس را مشخص می کند



در ادامه، روش استفاده از متدهای GetMethods و GetProperties را همراه با مثال بیان می کنیم. روش استفاده از متدهای دیگر نیز مشابه این متدهاست.

1) GetMethods: متد GetMethods متدهای عمومی (public) یک کلاس را تحت قالب یک آرایه از اشیاء MethodInfo بر می گرداند. هر شیء MethodInfo شامل اطلاعات یک متد (مانند نام متد، نوع ورودی ها، نوع خروجی و غیره) از یک کلاس است. به مثال زیر دقت کنید:



class Page

{

public void Refresh() { ... }

public void DrawText() { ... }

public void DrawImage() { ... }

private string GetHeader() { ... }

public static Page GetEmptyPage() { ... }

}



class Program

{

static void Main()

{

Page p = new Page();

CallDrawMethods(p);

}



public static void CallDrawMethods(object obj)

{

Type t = obj.GetType();

MethodInfo[] methods = t.GetMethods();

foreach (MethodInfo m in methods)

if (m.Name.StartsWith("Draw"))

m.Invoke(obj);

}

}



در این مثال ابتدا یک شیء از کلاس Page ایجاد شده و سپس به متد CallDrawMethods ارسال می شود. متد CallDrawMethods بدون اینکه از نوع شیء ارسال شده اطلاعی داشته باشد نوع آن را در داخل متغیر t قرار می دهد؛ سپس توسط متد GetMethods کلیه ی متدهای عمومی (public) کلاس Page در داخل یک آرایه با نام methods ریخته می شود و در نهایت هر کدام از متدهای کلاس Page که نام آنها با Draw شروع می شود توسط متد Invoke فراخوانی می شوند. Invoke یک شیء از کلاس Page را دریافت و متد مربوطه را در آن شیء اجرا می کند. بنابراین در مثال فوق فقط متدهای DrawText و DrawImage از شیء obj بصورت غیر مستقیم فراخوانی می شوند. از این طریق می توان متدهای اشیاء دیگر که از کلاسهای متفاوتی هستند را نیز فراخوانی کرد.



متد GetMethods یک Overload دیگر نیز دارد که از طریق ارسال یک پارامتر BindingFlags به آن می توان به متدهایی غیر از متدهای عمومی (مثلاً متدهای static و private) یک کلاس نیز دسترسی داشت. در مثال فوق، اطلاعات متدهای GetHeader و GetEmptyPage در داخل آرایه ی methods ریخته نمی شوند، زیرا یکی به صورت خصوصی (private) و دیگری نیز به صورت ایستا (static) تعریف شده است. برای جستجوی متد های فوق باید پارامتر BindingFlags را به صورت زیر به GetMethods ارسال کرد:



برای جستجوی متد GetHeader

t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);



برای جستجوی متد GetEmptyPage

t.GetMethods(BindingFlags.Static);



دقت داشته باشید که BindingFlags یک داده ی شمارشی (enum) است و اگر می خواهید دامنه ی جستجو را وسیعتر کنید، باید حالتهای مختلف آن را با یکدیگر OR کنید؛ همچنین این نکته را یادآور می شویم که GetMethods، سازنده های کلاس (Constructors) و همچنین متدهای get و set هر یک از خصوصیات کلاس را نیز بر می گرداند. بنابراین دقت داشته باشید که همانند مثال فوق، قبل از استفاده از شیء MethodInfo نام آن را با یک شرط تست کنید.



2) GetProperties: متد GetProperties نیز خصوصیات عمومی (public) یک کلاس را تحت قالب یک آرایه از اشیاء PropertyInfo بر می گرداند. PropertyInfo شامل اطلاعات یک خصوصیت (مانند نام، نوع، مقدار و غیره) است. مثال زیر را درنظر بگیرید:



class Book

{

private string _name;

public string Name

{

get { return _name; }

set { _name = value; }

}

private int _price;

public int Price

{

get { return _price; }

set { _price = value; }

}

}



class Program

{

static void Main()

{

Book b = new Book();

b.Name = "Reflection in .NET";

b.Price = 40;

string sql = BuildQuery(b);

Console.Write(sql);

}



public static string BuildQuery(object obj)

{

Type t = obj.GetType();

string sql = "SELECT * FROM " + t.Name;

sql += " WHERE ";

PropertyInfo[] properties = t.GetProperties();



foreach (PropertyInfo p in properties)

if (p.PropertyType == typeof(int))

{

sql += p.Name + " = " + p.GetValue(obj, null);

sql += " AND ";

}

else if (p.PropertyType == typeof(string))

{

sql += p.Name + " = '" + p.GetValue(obj, null) + "'";

sql += " AND ";

}



//removing last " AND " from string

return sql.Substring(0, sql.Length - 5);

}

}



در مثال فوق ابتدا یک شیء از کلاس Book ایجاد شده و خصوصیات آن مقدار دهی می شوند. سپس توسط متد BuildQuery، دستور SQL برای جستجوی رکورد این کتاب ساخته می شود. متد GetProperties، تمام خصوصیات عمومی (public) کلاس Book را تحت قالب آرایه ای از اشیاء PropertyInfo بر می گرداند. هر شیء PropertyInfo شامل PropertyType و Name است که به ترتیب نوع و نام هر خصوصیت را در یک کلاس مشخص می کند. در مثال بالا برای کلاس Book دو نمونه از شیء PropertyInfo در آرایه ی properties ایجاد می شود و سپس برای هر کدام از این دو شیء، دستور SQL مناسب ساخته می شود. از متد GetValue نیز برای خواندن مقدار یک خصوصیت در یک شیء استفاده می شود، بنابراین شیء مورد نظر را باید به این متد ارسال کنید. در متد GetProperties هم همانند GetMethods قابلیت استفاده از پارامتر BindingFlags را دارید. در نهایت، با اجرای مثال بالا عبارت زیر در خروجی نمایش داده خواهد شد:



SELECT * FROM Book WHERE Name = 'Reflection in .NET' AND Price = 40

لطفا دوستان ديگه هم اگر اطلاعات كاملتري دارند دريغ نكنند .

موفق باشيد