PDA

View Full Version : حرفه ای: اجرای Runtime کدها



navidkhalilian
جمعه 02 مهر 1389, 00:01 صبح
سلام دوستان.من می خوام یکی از تابع های برنامه رو داخل یک متغر رشته ای بنویسم و هنگام اجرای برنامه بگم اون تابه از داخل اون متغیر رشته ای اجرا بشه.مثل زیر:



string a="private static bool Main(int b) {"+
if(){b==1} return true } ";


private void btn1_Click(object sender, EventArgs e)
{
اینجا بگم که تابعی که داخل رشته بالا نوشته رو اجرا کن و نتیجه تابع رو چاپ کن
}

mehdi.mousavi
جمعه 02 مهر 1389, 01:07 صبح
سلام دوستان.من می خوام یکی از تابع های برنامه رو داخل یک متغر رشته ای بنویسم و هنگام اجرای برنامه بگم اون تابه از داخل اون متغیر رشته ای اجرا بشه.

سلام.
لطفا به این مقاله (http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm) رجوع کنید.

موفق باشید.

navidkhalilian
جمعه 02 مهر 1389, 16:25 عصر
دوست عزیز این کد ها رو خودم قبلا دیدم.اما مشکل اینجاست که این کد ها تابع رو اجرا نمیکنه اینا یک namespace رو اجرا میکنه و من نمی دونم چطوری مقدار تابع رو برگردونم به برنامه.ممنون میشم راهنمایی کنید.

r00tkit
جمعه 02 مهر 1389, 17:02 عصر
اقای موسوی من این مقاله ای که معرفی کردین رو نخوندم فقط یه نگاه کوچیکی که به کد هاش انداختم

حالا با این روش می شه کدی رو اجرا کرد که مربوط به همین برنامه(برنامه ای که کد ها توی متغیر رشته ای ان قرار دارن) باشه مثلا" کدی بنویسیم که یه باتون به برنامه add کنه
یه چیزی تو این مایه ها ( کد تعییر به اصل برنامه بده نه جدا اجرا بشه) با این روش حتما" باید کلاسی باشه و توش یه متود و ان متود اجرا بشه


Button button1 = new Button ();
....

this.Controls.Add(button1);

این this به فورم اصلی اشاره کنه
به عبارتی تابع نوشته شده به کلاس موجود اضافه بشه نه اینکه یه کلاس جدا ایجاد بشه (نمی دونم که این کد های اجرایی( داینامیک) توی فضای همین پروسس(اجرا کنندهی کدهای داینامیک) اجرا می شه یا نه )

فکر کنم نشه؟

ببخشید زیاد توضیح دادم

navidkhalilian
شنبه 03 مهر 1389, 17:29 عصر
اقای موسوی من این مقاله ای که معرفی کردین رو نخوندم فقط یه نگاه کوچیکی که به کد هاش انداختم

حالا با این روش می شه کدی رو اجرا کرد که مربوط به همین برنامه(برنامه ای که کد ها توی متغیر رشته ای ان قرار دارن) باشه مثلا" کدی بنویسیم که یه باتون به برنامه add کنه
یه چیزی تو این مایه ها ( کد تعییر به اصل برنامه بده نه جدا اجرا بشه) با این روش حتما" باید کلاسی باشه و توش یه متود و ان متود اجرا بشه


Button button1 = new Button ();
....

this.Controls.Add(button1);

این this به فورم اصلی اشاره کنه
به عبارتی تابع نوشته شده به کلاس موجود اضافه بشه نه اینکه یه کلاس جدا ایجاد بشه (نمی دونم که این کد های اجرایی( داینامیک) توی فضای همین پروسس(اجرا کنندهی کدهای داینامیک) اجرا می شه یا نه )

فکر کنم نشه؟

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

mehdi.mousavi
شنبه 03 مهر 1389, 22:51 عصر
فکر کنم نشه؟ ببخشید زیاد توضیح دادم


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

سلام.
البته که میشه... من کد مزبور رو تغییر دادم تا اینکارو انجام بده (البته برای خوانایی، Error Handling اش رو حذف کردم که طبیعتا شما باید در Production Code اتون اونها رو در نظر بگیرید).

برای آزمایش، یه فرم ایجاد کردم که روی اون یک Button گذاشتم. با زدن این دکمه، کدی بصورت Dynamic کامپایل میشه، که این کد، Button دومی رو ایجاد میکنه و به همین فرم اضافه میکنه. Click Handler دکمه اصلی رو بدین صورت پیاده سازی کردم:

private void btnAddSecondButtonToForm_Click(object sender, EventArgs e)
{
CSharpCodeProvider compiler = new CSharpCodeProvider();
CompilerParameters references = new CompilerParameters();

references.ReferencedAssemblies.Add("System.dll");
references.ReferencedAssemblies.Add("System.Windows.Forms.dll");
references.GenerateInMemory = false;

string lcCode = @"using System;
using System.Windows.Forms;
namespace MyNamespace {
public class MyClass {
public void AddButton(Form parent) {
Button button = new Button();
button.Text = ""Second Button"";
parent.Controls.Add(button);
}
}
}";


CompilerResults compilerResults = compiler.CompileAssemblyFromSource(references, lcCode);
if (compilerResults.Errors.HasErrors)
return;

Assembly assembly = compilerResults.CompiledAssembly;

object obj = assembly.CreateInstance("MyNamespace.MyClass");
if (obj == null)
return;

obj.GetType().InvokeMember("AddButton", BindingFlags.InvokeMethod, null, obj, new object[] { this });
}


در این کد، من یک تابع AddButton دارم (که در اون string می تونید ببینید) که پارامتری از نوع Form میگیره (که در خط آخر، this رو دارم به اون کد پاس میکنم). به این ترتیب، کد Dynamic ایجاد شده، به این Form دسترسی خواهد داشت. با استفاده از اون پارامتر، حالا میتونم توی کد Dynamic ام، Button جدیدی ایجاد کنم و به فرم اصلی اضافه اش کنم.

موفق باشید.

navidkhalilian
سه شنبه 06 مهر 1389, 13:13 عصر
سلام.
البته که میشه... من کد مزبور رو تغییر دادم تا اینکارو انجام بده (البته برای خوانایی، Error Handling اش رو حذف کردم که طبیعتا شما باید در Production Code اتون اونها رو در نظر بگیرید).

برای آزمایش، یه فرم ایجاد کردم که روی اون یک Button گذاشتم. با زدن این دکمه، کدی بصورت Dynamic کامپایل میشه، که این کد، Button دومی رو ایجاد میکنه و به همین فرم اضافه میکنه. Click Handler دکمه اصلی رو بدین صورت پیاده سازی کردم:

private void btnAddSecondButtonToForm_Click(object sender, EventArgs e)
{
CSharpCodeProvider compiler = new CSharpCodeProvider();
CompilerParameters references = new CompilerParameters();

references.ReferencedAssemblies.Add("System.dll");
references.ReferencedAssemblies.Add("System.Windows.Forms.dll");
references.GenerateInMemory = false;

string lcCode = @"using System;
using System.Windows.Forms;
namespace MyNamespace {
public class MyClass {
public void AddButton(Form parent) {
Button button = new Button();
button.Text = ""Second Button"";
parent.Controls.Add(button);
}
}
}";


CompilerResults compilerResults = compiler.CompileAssemblyFromSource(references, lcCode);
if (compilerResults.Errors.HasErrors)
return;

Assembly assembly = compilerResults.CompiledAssembly;

object obj = assembly.CreateInstance("MyNamespace.MyClass");
if (obj == null)
return;

obj.GetType().InvokeMember("AddButton", BindingFlags.InvokeMethod, null, obj, new object[] { this });
}


در این کد، من یک تابع AddButton دارم (که در اون string می تونید ببینید) که پارامتری از نوع Form میگیره (که در خط آخر، this رو دارم به اون کد پاس میکنم). به این ترتیب، کد Dynamic ایجاد شده، به این Form دسترسی خواهد داشت. با استفاده از اون پارامتر، حالا میتونم توی کد Dynamic ام، Button جدیدی ایجاد کنم و به فرم اصلی اضافه اش کنم.

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

button.Location = new System.Drawing.Point(10, 10);

button.Size = new System.Drawing.Size(10, 10);

mehdi.mousavi
سه شنبه 06 مهر 1389, 13:58 عصر
دوست عزیز این برنامه رو من اجرا کردم ولی هیچ اتفاقی نمی افته.شما مطمئنی جواب داده؟؟؟؟من این دو خط رو اضافه کردم که دکمه رو رسم ونمایش بده اما نشد.

button.Location = new System.Drawing.Point(10, 10);
button.Size = new System.Drawing.Size(10, 10);


سلام.
البته که مطمئنم! کد شما کار نمیکنه چون دارید از System.Drawing استفاده می کنید و اونو حتما به لیست Reference های برنامه ای که قصد Compile اونو دارید، اضافه نکرده اید. شما باید خط زیر رو به برنامه اضافه کنید (در جایگاه درست، زیر اونیکی Reference هایی که من گذاشتم):

references.ReferencedAssemblies.Add("System.Drawing.dll");

تا بتونید از System.Drawing Namespace اضافه کنید. اینم تصویری از خروجی برنامه:


http://barnamenevis.org/forum/attachment.php?attachmentid=57245&stc=1&d=1285671420


موفق باشید.

navidkhalilian
چهارشنبه 07 مهر 1389, 16:37 عصر
سلام.من به جای تابع addbutton این تابع رو اضافه کردم.اما نمیدونم چطوری باید خروجی تابع رو برگردونم.میشه راهنمایی کنید؟

public string sum(Form parent,int a,int b) {
int c=a+b;
return c;

}
این خط رو هم تغییر دادم
obj.GetType().InvokeMember("sum", BindingFlags.InvokeMethod, null, obj, new object[] { this, 10, 20 });
مقدار 10و20 را اضافه کردم

mehdi.mousavi
چهارشنبه 07 مهر 1389, 16:44 عصر
سلام.من به جای تابع addbutton این تابع رو اضافه کردم.اما نمیدونم چطوری باید خروجی تابع رو برگردونم.میشه راهنمایی کنید؟


سلام.
بدین شکل عمل کنید:

CSharpCodeProvider compiler = new CSharpCodeProvider();
CompilerParameters references = new CompilerParameters();

references.ReferencedAssemblies.Add("System.dll");
references.ReferencedAssemblies.Add("System.Windows.Forms.dll");
references.ReferencedAssemblies.Add("System.Drawing.dll");
references.GenerateInMemory = false;

string lcCode = @"using System;
using System.Windows.Forms;
namespace MyNamespace {
public class MyClass {
public int Sum(Form parent, int a, int b) {
return a + b;
}
}
}";


CompilerResults compilerResults = compiler.CompileAssemblyFromSource(references, lcCode);
if (compilerResults.Errors.HasErrors)
return;

Assembly assembly = compilerResults.CompiledAssembly;

object obj = assembly.CreateInstance("MyNamespace.MyClass");
if (obj == null)
return;

object returnValue = obj.GetType().InvokeMember("Sum", BindingFlags.InvokeMethod, null, obj, new object[] { this, 10, 20 });
if (returnValue != null)
{
int sum = Convert.ToInt32(returnValue);
}


موفق باشید.

mehdi.mousavi
چهارشنبه 07 مهر 1389, 22:37 عصر
دوست عزیز میشه مرجعی که از روش کمک میگیری رو به ما هم معرفی کنید.تشکر

سلام.
من در اولین پاسخ به این تاپیک، لینکی دادم (http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm) که متاسفانه شما مطالعه نکردید (یا درست مطالعه نکردید) و از اون پس کلیه پستهای این تاپیک، به نوعی تکرار مکررات شدش. توضیح کلیه این کلاسها، متودها، روشها و ... در MSDN وجود داره. کافیه Namespace مربوطه رو در MSDN جستجو کنید البته در این مورد خاص، اون مثال اونقدر گویا و کلی نوشته شده که جایی برای سوالات دیگه باقی نمیذاره.

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

موفق باشید.

r00tkit
یک شنبه 18 مهر 1389, 19:13 عصر
سلام


استاد موسوی بعد 10 روز جوابتون رو دیدم

هر چند استفاده از Reflectionترفندی خوبی بود ممنون ولی من منظورم این بود که به طور داینامیک کد های خود برنامه اصلی عوض بشه مثلا ruby نه اینکه بازم از کدهای اسمبلی دیگه استفاده کنیم به عبارت مثال دیگه( عجب جملهی ای شد:خجالت:) طوری مثلا" یه تابع رو به کلاس موحود اضافه کنیم

خط اخر مثالتون هم اگه این طوری بشه بهتر نبود(درستش کدوم روش هستش ؟ ) ؟( استفاده از dynamic به جای Reflection






object obj = assembly.CreateInstance("MyNamespace.MyClass");
if (obj == null)
return;
obj.GetType().InvokeMember("AddButton", BindingFlags.InvokeMethod, null, obj, new object[] { this });






dynamic obj2 = assembly.CreateInstance("MyNamespace.MyClass");
obj2.AddButton(this);
// کوتاه شده

mehdi.mousavi
دوشنبه 19 مهر 1389, 10:04 صبح
سلام استاد موسوی بعد 10 روز جوابتون رو دیدم هر چند استفاده از Reflectionترفندی خوبی بود ممنون ولی من منظورم این بود که به طور داینامیک کد های خود برنامه اصلی عوض بشه مثلا ruby نه اینکه بازم از کدهای اسمبلی دیگه استفاده کنیم به عبارت مثال دیگه( عجب جملهی ای شد:خجالت:) طوری مثلا" یه تابع رو به کلاس موحود اضافه کنیم.

سلام.
چند بار مجبور شدم بخونم تا متوجه بشم چی میگید. (واقعا عجب جمله ای بود :چشمک:). تنها راه ایجاد یه Assembly ی جدید هستش، بدین ترتیب که در اون با استفاده از partial class ها، قابلیت مورد نظر رو به کلاس فعلی اضافه کنیم، اما دقت کنید که این قابلیت جدید اضافه شده نیز فقط در Assembly ی جدید در دسترس خواهد بود...


خط اخر مثالتون هم اگه این طوری بشه بهتر نبود(درستش کدوم روش هستش ؟) ؟( استفاده از dynamic به جای Reflection

در .NET Framework 4 بله، چون کدهای Boilerplate از بین میره و کد بسیار خواناتر میشه. اما عموم افرادیکه من میشناسم نمیتونن با این سرعت به اون نسخه کوچ کنن.

موفق باشید.