در دات نت فریم ورک امکان کامپایل پویای یک قطعه کد دریافت شده از یک رشته، توسط فضای نام 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();
}
}
}
کد مورد نظر را به صورت یک فایل 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- دادن اجازهی کد نویسی به کاربران برنامهی خود (شبیه به سیستمهای ماکرو و اسکریپت نویسی موجود)
و ...
بازخوردهای دوره
ارتباطات بلادرنگ و SignalR
- نیازی به سرفصل جدا ندارد با توجه به خودکار بودن انتخاب لایه انتقال بر اساس توانایی سکوی کاری مورد استفاده (در حین کار با SignalR، وب سوکت فقط در ویندوز 8، IIS8 به همراه پروژهای مبتنی بر دات نت 4 و نیم پشتیبانی میشود). سایر بحثها و نکات یکی است و تفاوتی نمیکند. زمانیکه با Hub کار میکنید در لایهای قرار دارید که این جزئیات از شما مخفی میشود و کار انتخاب خودکار است (تصویر abstraction level مطلب جاری).
+ دورهها در سایت قسمتی دارند جهت پرسش و پاسخ اختصاصی که میشود مشکلات و سؤالات مرتبط به دوره را در آنجا ارسال کرد با توضیح بیشتر.
+ دورهها در سایت قسمتی دارند جهت پرسش و پاسخ اختصاصی که میشود مشکلات و سؤالات مرتبط به دوره را در آنجا ارسال کرد با توضیح بیشتر.
- Velocity CTP3 ارائه شد.
پروژه سورس بازی است که از بسیاری از ماژولهای جدید دات نت فریم ورک استفاده میکند و نکتهی جالب نگارش جدید آن مهاجرت از MS Ajax به jQuery Ajax است (قسمت اجکس آن کلا از صفر بر اساس jQuery بازنویسی شده است).
- چک لیستی که پیش از برپایی یک وب سایت باید بررسی شود.
- نگارش بتا Ext Core 3.0 ارائه شد.
- یک سری برگههای مرجع لینوکسی!
- دمویی در مورد ویندوز Azure و سرویسهای مبتنی بر آن
سه نکته مهم حین توزیع برنامههای ASP.NET 4.0 بر روی IIS 6.0 نسبت به سایر نگارشهای قبلی وجود دارند که باید در نظر گرفته شوند:
الف) پس از اتقای برنامه از نگارشهای قبلی به دات نت 4 (با فرض اینکه دات نت 4 بر روی سرور نصب است)، پیغام 404 یا به عبارتی فایل مورد نظر بر روی سرور یافت نشد را دریافت میکنید (با تمام فایلهای موجود):
در کنسول IIS ، ذیل قسمت Web Services Extensions ، باید دو مورد از حالت prohibited خارج شوند:
- All unknown ISAPI extensions
- ASP.NET 4.0
ب) پس از اجرای برنامه پیغام غیر معتبر بودن تگهای جدید فایل Web.Config را ملاحظه میکنید:
- در برگهی خواص سایت در IIS 6.0 ، اکنون امکان انتخاب ASP.NET 4.0 هم میسر است که حتما باید این مورد انتخاب گردد (تا دات نت سه و نیم این نام تنها ASP.NET 2.0 بود). در غیر اینصورت تگهای جدید فایل Web.Config شناخته نخواهند شد.
ج) بلافاصله پس از اجرای برنامه، پیغام Server Application Unavailable قابل مشاهده است:
نکتهی مهم دیگری که به همراه برنامههای دات نت 4 باید به آن توجه داشت، ضرورت اجرای آنها در یک پروسه جدید است. پروسه جدید در IIS 6.0 به معنای یک Application pool جدید است. به عبارتی اگر هم اکنون بر روی IIS 6.0 شما برای مثال 2 برنامهی دات نت سه و دات نت 4 قصد استفاده از یک Application pool را داشته باشند، پیغام Server Application Unavailable ظاهر خواهد شد، زیرا نمیتوان این دو نگارش را تحت یک پروسه اجرا کرد. برای حل این مشکل باید یک Application pool جدید و اختصاصی را جهت برنامهی ASP.Net 4.0 خود تعریف و انتساب دهید.
اشتراکها
ReSharper 8.2.1 منتشر شد
لیست موارد برطرف شده Resharper 8.2.1 در اینجا
در WPF، زیر ساختهای ComponentModel توسط کلاسی به نام PropertyDescriptor، منابع Binding موجود در قسمتهای مختلف برنامه را در جدولی عمومی ذخیره و نگهداری میکند. هدف از آن، مطلع بودن از مواردی است که نیاز دارند توسط مکانیزمهایی مانند INotifyPropertyChanged و DependencyProperty ها، اطلاعات اشیاء متصل را به روز کنند.
در این سیستم، کلیه اتصالاتی که Mode آنها به OneTime تنظیم نشده است، به صورت اجباری دارای یک valueChangedHandlers متصل توسط سیستم PropertyDescriptor خواهند بود و در حافظه زنده نگه داشته میشوند؛ تا بتوان در صورت نیاز، توسط سیستم binding اطلاعات آنها را به روز کرد.
همین مساله سبب میشود تا اگر قرار نیست خاصیتی برای نمونه توسط مکانیزم INotifyPropertyChanged اطلاعات UI را به روز کند (یک خاصیت معمولی دات نتی است) و همچنین حالت اتصال آن به OneTime نیز تنظیم نشده، سبب مصرف حافظه بیش از حد برنامه شود.
اطلاعات بیشتر
A memory leak may occur when you use data binding in Windows Presentation Foundation
راه حل آن هم ساده است. برای اینکه valueChangedHandler ایی به خاصیت سادهای که قرار نیست بعدها UI را به روز کند، متصل نشود، حالت اتصال آنرا باید به OneTime تنظیم کرد.
سؤال: در یک برنامه بزرگ که هم اکنون مشغول به کار است، چطور میتوان این مسایل را ردیابی کرد؟
برای دستیابی به اطلاعات کش Binding در WPF، باید به Reflection متوسل شد. به این ترتیب در برنامه جاری، در کلاس PropertyDescriptor به دنبال یک کلاس خصوصی تو در توی دیگری به نام ReflectTypeDescriptionProvider خواهیم گشت (این اطلاعات از طریق مراجعه به سورس دات نت و یا حتی برنامههای ILSpy و Reflector قابل استخراج است) و سپس در این کلاس خصوصی داخلی، فیلد خصوصی propertyCache آنرا که از نوع HashTable است استخراج میکنیم:
اکنون به لیست داخلی Binding نگهداری شونده توسط WPF دسترسی پیدا کردهایم. در این لیست به دنبال مواردی خواهیم گشت که فیلد valueChangedHandlers به آنها متصل شده است و در حال گوش فرا دادن به سیستم binding هستند (سورس کامل و طولانی این مبحث را در پروژه پیوست شده میتوانید ملاحظه کنید).
یک مثال: تعریف یک کلاس ساده، اتصال آن و سپس بررسی اطلاعات درونی سیستم Binding
فرض کنید یک کلاس مدل ساده به نحو ذیل تعریف شده است:
سپس این کلاس به صورت یک List، توسط ViewModel برنامه در اختیار View متناظر با آن قرار میگیرد:
تعاریف View برنامه نیز به نحو زیر است:
همه چیز در آن معمولی به نظر میرسد. ابتدا به ViewModel برنامه دسترسی یافته و DataContext را با آن مقدار دهی میکنیم. سپس اطلاعات این لیست را توسط یک ListBox نمایش خواهیم داد.
خوب؛ اکنون اگر اطلاعات HashTable داخلی سیستم Binding را در مورد View فوق بررسی کنیم به شکل زیر خواهیم رسید:
بله. تعداد زیادی خاصیت Name زنده و موجود در حافظه باقی هستند که تحت ردیابی سیستم Binding میباشند.
در ادامه، نکتهی ابتدای بحث را جهت تعیین حالت Binding به OneTime، به View فوق اعمال میکنیم (یک سطر ذیل باید تغییر کند):
در این حالت اگر نگاهی به سیستم ردیابی WPF داشته باشیم، دیگر خبری از اشیاء زنده دارای خاصیت Name در حال ردیابی نیست:
به این ترتیب میتوان در لیستهای طولانی، به مصرف حافظه کمتری در برنامه WPF خود رسید.
بدیهی است این نکته را تنها در مواردی میتوان اعمال کرد که نیاز به بهروز رسانیهای ثانویه اطلاعات UI در کدهای برنامه وجود ندارند.
چطور از این نکته برای پروفایل یک برنامه موجود استفاده کنیم؟
کدهای برنامه را از انتهای بحث دریافت کنید. سپس دو فایل ReflectPropertyDescriptorWindow.xaml و ReflectPropertyDescriptorWindow.xaml.cs آنرا به پروژه خود اضافه نمائید و در سازنده پنجره اصلی برنامه، کد ذیل را فراخوانی نمائید:
کمی با برنامه کار کرده و منتظر شوید تا لیست نهایی اطلاعات داخلی Binding ظاهر شود. سپس مواردی را که دارای HandlerCount بالا هستند، مدنظر قرار داده و بررسی نمائید که آیا واقعا این اشیاء نیاز به valueChangedHandler متصل دارند یا خیر؟ آیا قرار است بعدها UI را از طریق تغییر مقدار خاصیت آنها به روز نمائیم یا خیر. اگر خیر، تنها کافی است نکته Mode=OneTime را به این Bindingها اعمال نمائیم.
دریافت کدهای کامل پروژه این مطلب
WpfOneTime.zip
در این سیستم، کلیه اتصالاتی که Mode آنها به OneTime تنظیم نشده است، به صورت اجباری دارای یک valueChangedHandlers متصل توسط سیستم PropertyDescriptor خواهند بود و در حافظه زنده نگه داشته میشوند؛ تا بتوان در صورت نیاز، توسط سیستم binding اطلاعات آنها را به روز کرد.
همین مساله سبب میشود تا اگر قرار نیست خاصیتی برای نمونه توسط مکانیزم INotifyPropertyChanged اطلاعات UI را به روز کند (یک خاصیت معمولی دات نتی است) و همچنین حالت اتصال آن به OneTime نیز تنظیم نشده، سبب مصرف حافظه بیش از حد برنامه شود.
اطلاعات بیشتر
A memory leak may occur when you use data binding in Windows Presentation Foundation
راه حل آن هم ساده است. برای اینکه valueChangedHandler ایی به خاصیت سادهای که قرار نیست بعدها UI را به روز کند، متصل نشود، حالت اتصال آنرا باید به OneTime تنظیم کرد.
سؤال: در یک برنامه بزرگ که هم اکنون مشغول به کار است، چطور میتوان این مسایل را ردیابی کرد؟
برای دستیابی به اطلاعات کش Binding در WPF، باید به Reflection متوسل شد. به این ترتیب در برنامه جاری، در کلاس PropertyDescriptor به دنبال یک کلاس خصوصی تو در توی دیگری به نام ReflectTypeDescriptionProvider خواهیم گشت (این اطلاعات از طریق مراجعه به سورس دات نت و یا حتی برنامههای ILSpy و Reflector قابل استخراج است) و سپس در این کلاس خصوصی داخلی، فیلد خصوصی propertyCache آنرا که از نوع HashTable است استخراج میکنیم:
var reflectTypeDescriptionProvider = typeof(PropertyDescriptor).Module.GetType("System.ComponentModel.ReflectTypeDescriptionProvider"); var propertyCacheField = reflectTypeDescriptionProvider.GetField("_propertyCache", BindingFlags.Static | BindingFlags.NonPublic);
اکنون به لیست داخلی Binding نگهداری شونده توسط WPF دسترسی پیدا کردهایم. در این لیست به دنبال مواردی خواهیم گشت که فیلد valueChangedHandlers به آنها متصل شده است و در حال گوش فرا دادن به سیستم binding هستند (سورس کامل و طولانی این مبحث را در پروژه پیوست شده میتوانید ملاحظه کنید).
یک مثال: تعریف یک کلاس ساده، اتصال آن و سپس بررسی اطلاعات درونی سیستم Binding
فرض کنید یک کلاس مدل ساده به نحو ذیل تعریف شده است:
namespace WpfOneTime.Models { public class User { public string Name { set; get; } } }
using WpfOneTime.Models; using System.Collections.Generic; namespace WpfOneTime.ViewModels { public class MainWindowViewModel { public IList<User> Users { set; get; } public MainWindowViewModel() { Users = new List<User>(); for (int i = 0; i < 1000; i++) { Users.Add(new User { Name = "name " + i }); } } } }
<Window x:Class="WpfOneTime.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ViewModels="clr-namespace:WpfOneTime.ViewModels" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <ViewModels:MainWindowViewModel x:Key="vmMainWindowViewModel" /> </Window.Resources> <Grid DataContext="{Binding Source={StaticResource vmMainWindowViewModel}}"> <ListBox ItemsSource="{Binding Users}"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Window>
خوب؛ اکنون اگر اطلاعات HashTable داخلی سیستم Binding را در مورد View فوق بررسی کنیم به شکل زیر خواهیم رسید:
بله. تعداد زیادی خاصیت Name زنده و موجود در حافظه باقی هستند که تحت ردیابی سیستم Binding میباشند.
در ادامه، نکتهی ابتدای بحث را جهت تعیین حالت Binding به OneTime، به View فوق اعمال میکنیم (یک سطر ذیل باید تغییر کند):
<TextBlock Text="{Binding Name, Mode=OneTime}" />
به این ترتیب میتوان در لیستهای طولانی، به مصرف حافظه کمتری در برنامه WPF خود رسید.
بدیهی است این نکته را تنها در مواردی میتوان اعمال کرد که نیاز به بهروز رسانیهای ثانویه اطلاعات UI در کدهای برنامه وجود ندارند.
چطور از این نکته برای پروفایل یک برنامه موجود استفاده کنیم؟
کدهای برنامه را از انتهای بحث دریافت کنید. سپس دو فایل ReflectPropertyDescriptorWindow.xaml و ReflectPropertyDescriptorWindow.xaml.cs آنرا به پروژه خود اضافه نمائید و در سازنده پنجره اصلی برنامه، کد ذیل را فراخوانی نمائید:
new ReflectPropertyDescriptorWindow().Show();
دریافت کدهای کامل پروژه این مطلب
WpfOneTime.zip
اشتراکها
نگارش جدید برنامه ILMerge منتشر شد
اطلاعات ریز و سورس کد مأموریت آپولو 11 روی سایت گیت هاب قرار دادهشده است و میتواند راهنمای خوبی برای محققان کشورهای تازهکار برای انجام مأموریتهای فضایی بهویژه ارسال انسان بهکرات دیگر باشد.
اشتراکها