PDA

View Full Version : حرفه ای: کامپایل کد در زمان اجرا



hojjatshariffam
دوشنبه 25 مرداد 1389, 12:09 عصر
سلام به دوستان حرفه ای ، نماز روزه هاتون قبول
من می خوام کدی رو در زمان اجرا تو یک rich TextBox وارد کنم و با زدن کلیدی کد، کامپایل و در نهایت در صورت لزوم اجرا بشه
اگه خطای سینتکسی یا سمنتیکی هم داشت نشون بده
این مرحله اول بود
تو مرحله دوم می خوام کد هایی که در زمان اجرا نوشتم رو به عنوان یک کلاس در برنامه درج کنه و توی لیستی بتونم کلاسهای ایجاد شده رو ببینم و از بینشون اونایی رو که لازم دارم رو انتحاب کنم .

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

gwbasic
دوشنبه 25 مرداد 1389, 12:33 عصر
از کلاسهای Microsoft.Build.BuildAction.Engine برای Build کردن
و از Project برای اضافه کردن هر ایتمی به پروژه می تونی استفاده کنی

ila_mata86
دوشنبه 25 مرداد 1389, 12:47 عصر
میشه کمی بیشتر توضیح بدید.

hojjatshariffam
دوشنبه 25 مرداد 1389, 15:45 عصر
تو msdn هم این حوزه نام رو گشتم ولی چیز زیادی نیافتم
میشه یه مثال کوچیک بزارین؟

hojjatshariffam
دوشنبه 25 مرداد 1389, 16:46 عصر
از کلاسهای Microsoft.Build.BuildAction.Engine برای Build کردن
و از Project برای اضافه کردن هر ایتمی به پروژه می تونی استفاده کنی
بعد از کلی این ور و اون ور کردن اسم ها ، فهمیدم که حوزه نام Microsoft.Build.BuildEngine منظور شما بوده
ولی تو dotNet 4.0 منسوخ شده

دوستان حرفه ای میشه یکم بیشتر توضیح بدند؟

r00tkit
دوشنبه 25 مرداد 1389, 17:10 عصر
از کلاسهای Microsoft.Build.BuildAction.Engine برای Build کردن
و از Project برای اضافه کردن هر ایتمی به پروژه می تونی استفاده کنی

MSBuild چه ربطی به تغییر ( اضافه کردن) کد در حال اجرا داره http://en.wikipedia.org/wiki/MSBuild

hojjatshariffam
دوشنبه 25 مرداد 1389, 23:17 عصر
MSBuild چه ربطی به تغییر ( اضافه کردن) کد در حال اجرا داره http://en.wikipedia.org/wiki/MSBuild

منم چیزی ازش نفهمیدم

کسی نظری نداره؟

saeedalg
چهارشنبه 27 مرداد 1389, 16:28 عصر
http://msdn.microsoft.com/en-us/library/saf5ce06.aspx

sh4mid
چهارشنبه 27 مرداد 1389, 16:41 عصر
كامپايل پوياي كد در دات نت
در دات نت فريم ورك امكان كامپايل پوياي يك قطعه كد دريافت شده از يك رشته، توسط فضاي نام CodeDom مهيا است كه قدرت قابل توجهي را در اختيار برنامه نويس قرار مي‌دهد.
مثال يك:
رشته زير را كامپايل كرده و تبديل به يك فايل exe كنيد:

string source =
@"
namespace Foo
{
public class Bar
{
static void Main(string[] args)
{
Bar.SayHello();
}
public static void SayHello()
{
System.Console.WriteLine(""Hello World"");
}
}
}
";
روش انجام كار به همراه توضيحات مربوطه به صورت كامنت:

using System;
using System.Collections.Generic;
//دو فضاي نامي كه براي اين منظور اضافه شده‌اند
using Microsoft.CSharp;
using System.CodeDom.Compiler;
namespace compilerTest
{
class Program
{
static void compileIt1()
{
//سورس كد ما جهت كامپايل
string source =
@"
namespace Foo
{
public class Bar
{
static void Main(string[] args)
{
Bar.SayHello();
}
public static void SayHello()
{
System.Console.WriteLine(""Hello World"");
}
}
}
";
//تعيين نگارش كامپايلر مورد استفاده
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v3.5"}
};
//تعيين اينكه كد ما سي شارپ است
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
//تعيين اينكه خروجي يك فايل اجرايي است بعلاوه مشخص سازي محل ذخيره سازي فايل نهايي
CompilerParameters compilerParams = new CompilerParameters
{
OutputAssembly = "D:\\Foo.EXE",
GenerateExecutable = true
};
//عمليات كامپايل در اينجا صورت مي‌گيرد
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
//اگر خطايي وجود داشته باشد نمايش داده خواهد شد
Console.WriteLine("Number of Errors: {0}", results.Errors.Count);
foreach (CompilerError err in results.Errors)
{
Console.WriteLine("ERROR {0}", err.ErrorText);
}
}
static void Main(string[] args)
{
compileIt1();
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
مثال 2:
كد مورد نظر را به صورت يك فايل dll كامپايل كنيد.
براي اين منظور تمامي مراحل مانند قبل است فقط GenerateExecutable ذكر شده به false تنظيم شده و نام خروجي نيز به foo.dll بايد تنظيم شود.
مثال 3:
كد مورد نظر را در حافظه كامپايل كرده (خروجي dll يا exe نمي‌خواهيم)، سپس متد SayHello آن را به صورت پويا فراخواني نموده و خروجي را نمايش دهيد.
در اين حالت روش كار همانند مثال 1 است با اين تفاوت كه GenerateInMemory = true و GenerateExecutable = false تنظيم مي‌شوند. همچنين جهت دسترسي به متد كلاس ذكر شده،‌ از قابليت‌هاي ريفلكشن موجود در دات نت فريم ورك استفاده خواهد شد.

using System;
using System.Collections.Generic;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
namespace compilerTest
{
class Program
{
static void compileIt2()
{
//سورس كد ما جهت كامپايل
string source =
@"
namespace Foo
{
public class Bar
{
static void Main(string[] args)
{
Bar.SayHello();
}
public static void SayHello()
{
System.Console.WriteLine(""Hello World"");
}
}
}
";
//تعيين نگارش كامپايلر مورد استفاده
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v3.5"}
};
//تعيين اينكه كد ما سي شارپ است
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
//نحوه تعيين مشخص سازي كامپايل در حافظه
CompilerParameters compilerParams = new CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false
};
//عمليات كامپايل در اينجا صورت مي‌گيرد
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
// اگر خطايي در كامپايل وجود نداشت متد دلخواه را فراخواني مي‌كنيم
if (results.Errors.Count == 0)
{
//استفاده از ريفلكشن براي دسترسي به متد و فراخواني آن
Type type = results.CompiledAssembly.GetType("Foo.Bar");
MethodInfo method = type.GetMethod("SayHello");
method.Invoke(null, null);
}
}
static void Main(string[] args)
{
compileIt2();
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
نكته: نحوه‌ي استفاده از اسمبلي‌هاي ديگر در رشته سورس كد خود
مثال:
اگر رشته سورس ما به صورت زير بوده و از اسمبلي System.Drawing.Dll نيز كمك گرفته باشد،‌

string source =
@"
namespace Foo
{
public class Bar
{
static void Main(string[] args)
{
Bar.SayHello();
}
public static void SayHello()
{
System.Console.WriteLine(""Hello World"");
var r = new System.Drawing.Rectangle(0,0,100,100);
System.Console.WriteLine(r);
}
}
}
";
هنگام كامپايل آن توسط روش مثال يك، با خطاي زير مواجه خواهيم شد.
Number of Errors: 1
ERROR The type or namespace name 'Drawing' does not exist in the namespace 'System' (are you missing an assembly reference?)
براي رفع اين مشكل و معرفي اين اسمبلي،‌ سطر زير بايد پس از تعريف compilerParams اضافه شود.
compilerParams.ReferencedAssemblies.Add("System.Drawing.Dll");
اكنون كد كامپايل شده و مشكلي نخواهد داشت.
نمونه‌اي ديگر از اين دست، استفاده از LINQ مي‌باشد. در اين حالت اسمبلي System.Core.Dll نيز به روش ذكر شده بايد معرفي گردد تا مشكلي در كامپايل كد رخ ندهد.
كاربردها:
1- استفاده در ابزارهاي توليد كد (براي مثال در برنامه Linqer از اين قابليت استفاده مي‌شود)
2- استفاده‌هاي امنيتي (ايجاد روش‌هاي توليد يك سريال به صورت پويا و كامپايل پوياي كد مربوطه در حافظه‌اي محافظت شده)
3- استفاده جهت مقاصد محاسباتي پيشرفته
4- دادن اجازه‌ي كد نويسي به كاربران برنامه‌ي خود (شبيه به سيستم‌هاي ماكرو و اسكريپت نويسي موجود)

از وبلاگ وحید نصیری :)

MSN_Issue
چهارشنبه 27 مرداد 1389, 17:49 عصر
آقا امکانش هست ، کد C++ رو هم کامپایل کنه ؟!!!
البته بیشتر میخوام خروجیش رو برام در بیاره .

hojjatshariffam
جمعه 29 مرداد 1389, 02:43 صبح
كامپايل پوياي كد در دات نت
در دات نت فريم ورك امكان كامپايل پوياي يك قطعه كد دريافت شده از يك رشته، توسط فضاي نام CodeDom مهيا است كه قدرت قابل توجهي را در اختيار برنامه نويس قرار مي‌دهد.
....
از وبلاگ وحید نصیری :)

ممنون دوست من که راهنمائی کردین
ولی یه نکته ای وجود داره (یعنی یه مشکل)
اونم اینه که source در کد زیر باید آدرس یک فایل باشد نه خود کد



provider.CompileAssemblyFromFile(compilerParams, source);


چطوری میشه حلش کرد ، آیا با ذخیره اونا تو یه فایل و با دادن آدرس اون میشه مشکلو حل کرد؟
الان می خوام این کارو بکنم ، جوابشو اینجا میزارم
ولی اگه از همونجا String برمی داشت خیلی بهتر و جالب تر می شد

hojjatshariffam
جمعه 29 مرداد 1389, 04:11 صبح
آخ ببخشید توجه نکردم
من از متد زیر استفاده کرده بودم



provider.CompileAssemblyFromFile()

که پارامتر ورودیش ، آدرس فایل کده
ولی با متد
provider.CompileAssemblyFromSource() میشه همون String رو کامپایل کرد

r00tkit
جمعه 29 مرداد 1389, 04:18 صبح
جواب دوستمون هیچ ربطی به سوال شما نداشت چون شما می خوای به برنامهی درحال اجرات بگی کدی رو اجرا کنه و به همون برنامه اضافه بشه (منظور کلاس ها و متود هایی که تو کد مورد نظر هستش و قراره برنامه اجرا کته)

این روش دوستمون داینامیک کد رو کامپایل می کنه ولی نه ان داینامیکی که شما منظورته ( این روش یه فایل جدا می سازه مثل اینه که از کامپایلر تو کدت استفاده کردی)
منظور شما اینه که برنامه مثل ربان های داینامیک باشه (ruby pythonو...) که در حال اجرا بودن می شه وضیعیت کلاس ها رو تغییر داد و یا کلاسی اضافه کرد



ولی اگه از همونجا String برمی داشت خیلی بهتر و جالب تر می شد


می شه این کار رو کرد ولی جواب اصلی شما نیست خودم اینجا نوشته بودم (http://barnamenevis.org/forum/showthread.php?t=207478)

:خوب دیگه برم سحری بخورم :)

gwbasic
جمعه 29 مرداد 1389, 06:33 صبح
سلام ، ببخشید که من دیر جواب می دم البته دوستمون CodeDom رو مطرح کردن که فکر می کنم نیاز شما رو پاسخ می ده اما دو کلاسی که من مطرح کردم رو بیشتر توضیح می دم :
1- کلاس Engine که دقیقا برای Build کردن استفاده می شه که البته من namspace اون رو اشتباه داده بودم که باید ببخشید تو msdn هم توضیحاتش موجوده البته در Net 4. نمی دونم، می شه بررسی کرد ...

2- کلاس Project برای کار با یک پروژه
حالا دلیل اینکه این دو کلاس رو معرفی کردم و CodeDom رو نه:
ببینید وقتی که شما کدی رو RunTime کامپایل می کنید و از Dll اون استفاده می کنید معمولا نیازه که شما اون کد رو برای استفاده بعدی داشته یاشید



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

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

hojjatshariffam
یک شنبه 31 مرداد 1389, 23:21 عصر
من مخلص همه دوستان هستم
ولی چیزی که تا حالا من انجام دادم اینه
کد رو تو RichTextBox وارد کردم (و بصورت پویا می تونم دستی تغییرش بدم)
بعد اون کدو کامپایل می کنم و توسط ریفلکشن بهش دسترسی دارم و اجراش می کنم
حالا چطور می تونم با Project که دوست خوبمون gwbasic (http://www.barnamenevis.org/forum/member.php?u=25140) فرموند ، به پروژم اضافه کنم تا یه سری WorkFlow رو برام انجام بده
بزارید بیشتر توضیح بدم:
با جنرتور یه سری کد تولید می کنم اینا باید کامپایل بشه بعد به پروژه اضافه بشه، سپس با یه نوع جنریتور دیگه باید از این کلاسای قبلی استفاده کنم و یه یوزکیس رو پیاده سازی کنم ، کدهای جدیدی بوجود میاد که باید دوباره کامپایل بشن و به پروژه اضافه بشن بعد با کلیک مثلا یه کلید این جریان کاری انجام بشه و تمام.
اینا رو گفتم تا بیشتر روشن بشه که اینا رو برا چی می خوام
جنریتور رو با استفاده از جنریتور های دیگه و کمک استاد و بقیه دوستان سایت کم و بیش نوشتم ، کامپایل رو هم حل شده (با کمک شما ها) مونده بقیش
خودم دارم شب و روز کد تست می کنم و سرچ می کنم ولی یه نتیجه دپش هنوز نگرفتم
تا اینجاشم ممنونتون هستم
منتها بقیشم کمک کنید . مرسی ...

monirprogram
یک شنبه 02 مرداد 1390, 09:45 صبح
كامپايل پوياي كد در دات نت
در دات نت فريم ورك امكان كامپايل پوياي يك قطعه كد دريافت شده از يك رشته، توسط فضاي نام CodeDom مهيا است كه قدرت قابل توجهي را در اختيار برنامه نويس قرار مي‌دهد.
مثال يك:
رشته زير را كامپايل كرده و تبديل به يك فايل exe كنيد:

string source =
@"
namespace Foo
{
public class Bar
{
static void Main(string[] args)
{
Bar.SayHello();
}
public static void SayHello()
{
System.Console.WriteLine(""Hello World"");
}
}
}
";
روش انجام كار به همراه توضيحات مربوطه به صورت كامنت:

using System;
using System.Collections.Generic;
//دو فضاي نامي كه براي اين منظور اضافه شده‌اند
using Microsoft.CSharp;
using System.CodeDom.Compiler;
namespace compilerTest
{
class Program
{
static void compileIt1()
{
//سورس كد ما جهت كامپايل
string source =
@"
namespace Foo
{
public class Bar
{
static void Main(string[] args)
{
Bar.SayHello();
}
public static void SayHello()
{
System.Console.WriteLine(""Hello World"");
}
}
}
";
//تعيين نگارش كامپايلر مورد استفاده
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v3.5"}
};
//تعيين اينكه كد ما سي شارپ است
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
//تعيين اينكه خروجي يك فايل اجرايي است بعلاوه مشخص سازي محل ذخيره سازي فايل نهايي
CompilerParameters compilerParams = new CompilerParameters
{
OutputAssembly = "D:\\Foo.EXE",
GenerateExecutable = true
};
//عمليات كامپايل در اينجا صورت مي‌گيرد
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
//اگر خطايي وجود داشته باشد نمايش داده خواهد شد
Console.WriteLine("Number of Errors: {0}", results.Errors.Count);
foreach (CompilerError err in results.Errors)
{
Console.WriteLine("ERROR {0}", err.ErrorText);
}
}
static void Main(string[] args)
{
compileIt1();
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
مثال 2:
كد مورد نظر را به صورت يك فايل dll كامپايل كنيد.
براي اين منظور تمامي مراحل مانند قبل است فقط GenerateExecutable ذكر شده به false تنظيم شده و نام خروجي نيز به foo.dll بايد تنظيم شود.
مثال 3:
كد مورد نظر را در حافظه كامپايل كرده (خروجي dll يا exe نمي‌خواهيم)، سپس متد SayHello آن را به صورت پويا فراخواني نموده و خروجي را نمايش دهيد.
در اين حالت روش كار همانند مثال 1 است با اين تفاوت كه GenerateInMemory = true و GenerateExecutable = false تنظيم مي‌شوند. همچنين جهت دسترسي به متد كلاس ذكر شده،‌ از قابليت‌هاي ريفلكشن موجود در دات نت فريم ورك استفاده خواهد شد.

using System;
using System.Collections.Generic;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
namespace compilerTest
{
class Program
{
static void compileIt2()
{
//سورس كد ما جهت كامپايل
string source =
@"
namespace Foo
{
public class Bar
{
static void Main(string[] args)
{
Bar.SayHello();
}
public static void SayHello()
{
System.Console.WriteLine(""Hello World"");
}
}
}
";
//تعيين نگارش كامپايلر مورد استفاده
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v3.5"}
};
//تعيين اينكه كد ما سي شارپ است
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
//نحوه تعيين مشخص سازي كامپايل در حافظه
CompilerParameters compilerParams = new CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false
};
//عمليات كامپايل در اينجا صورت مي‌گيرد
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
// اگر خطايي در كامپايل وجود نداشت متد دلخواه را فراخواني مي‌كنيم
if (results.Errors.Count == 0)
{
//استفاده از ريفلكشن براي دسترسي به متد و فراخواني آن
Type type = results.CompiledAssembly.GetType("Foo.Bar");
MethodInfo method = type.GetMethod("SayHello");
method.Invoke(null, null);
}
}
static void Main(string[] args)
{
compileIt2();
Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}
نكته: نحوه‌ي استفاده از اسمبلي‌هاي ديگر در رشته سورس كد خود
مثال:
اگر رشته سورس ما به صورت زير بوده و از اسمبلي System.Drawing.Dll نيز كمك گرفته باشد،‌

string source =
@"
namespace Foo
{
public class Bar
{
static void Main(string[] args)
{
Bar.SayHello();
}
public static void SayHello()
{
System.Console.WriteLine(""Hello World"");
var r = new System.Drawing.Rectangle(0,0,100,100);
System.Console.WriteLine(r);
}
}
}
";
هنگام كامپايل آن توسط روش مثال يك، با خطاي زير مواجه خواهيم شد.
Number of Errors: 1
ERROR The type or namespace name 'Drawing' does not exist in the namespace 'System' (are you missing an assembly reference?)
براي رفع اين مشكل و معرفي اين اسمبلي،‌ سطر زير بايد پس از تعريف compilerParams اضافه شود.
compilerParams.ReferencedAssemblies.Add("System.Drawing.Dll");
اكنون كد كامپايل شده و مشكلي نخواهد داشت.
نمونه‌اي ديگر از اين دست، استفاده از LINQ مي‌باشد. در اين حالت اسمبلي System.Core.Dll نيز به روش ذكر شده بايد معرفي گردد تا مشكلي در كامپايل كد رخ ندهد.
كاربردها:
1- استفاده در ابزارهاي توليد كد (براي مثال در برنامه Linqer از اين قابليت استفاده مي‌شود)
2- استفاده‌هاي امنيتي (ايجاد روش‌هاي توليد يك سريال به صورت پويا و كامپايل پوياي كد مربوطه در حافظه‌اي محافظت شده)
3- استفاده جهت مقاصد محاسباتي پيشرفته
4- دادن اجازه‌ي كد نويسي به كاربران برنامه‌ي خود (شبيه به سيستم‌هاي ماكرو و اسكريپت نويسي موجود)

از وبلاگ وحید نصیری :)

واقعا عالی بود. مرسی. من 50% کارم راه افتاد:قلب::قلب: