اشتراکها
اشتراکها
دیتابیس coachbase برای اندروید
این مورد سمت ارسال java script است.
از سمت #c چطوری میشه هندل کرد
با تشکر از مطلب مفید شما
این کتابخانه در برنامه نویسی موبایل زامارین اندروید هم کاربرد داره ؟
استفاده از کامپایلر 1.1 برای پروژههای 1.1
اگر NET Core SDK. جدید را نصب کنید، سیستم build پروژه، به صورت خودکار از آخرین نگارش نصب شده استفاده میکند (یعنی نگارش 2). اگر میخواهید این مورد را بازنویسی کنید، نیاز است فایل ویژهای را به نام global.json با محتوای ذیل به ریشهی solution در بالاترین سطح ممکن اضافه کنید:
در اینجا عدد 1.0.4 شماره نگارش SDK مدنظر است. این شمارهها را در مسیر C:\Program Files\dotnet\sdk میتوانید مشاهده کنید و بر این اساس باید تصمیم گیری کنید (بر اساس شمارههای موجود و نصب شدهی بر روی سیستم شما).
و همچنین اگر فایل global.json را اضافه کردهاید، حین ارتقاء پروژه حتما باید شماره SDK موجود در آنرا به صورت دستی اصلاح کنید؛ وگرنه پروژه build نخواهد شد. عدم وجود این فایل به معنای استفادهی از آخرین شماره نگارش SDK موجود است.
اگر NET Core SDK. جدید را نصب کنید، سیستم build پروژه، به صورت خودکار از آخرین نگارش نصب شده استفاده میکند (یعنی نگارش 2). اگر میخواهید این مورد را بازنویسی کنید، نیاز است فایل ویژهای را به نام global.json با محتوای ذیل به ریشهی solution در بالاترین سطح ممکن اضافه کنید:
{ "sdk": { "version": "1.0.4" } }
و همچنین اگر فایل global.json را اضافه کردهاید، حین ارتقاء پروژه حتما باید شماره SDK موجود در آنرا به صورت دستی اصلاح کنید؛ وگرنه پروژه build نخواهد شد. عدم وجود این فایل به معنای استفادهی از آخرین شماره نگارش SDK موجود است.
مطالب
Span در C# 7.2
C# 7.2 به همراه تعداد کوچکی از بهبودهای کامپایلر است و با Visual Studio 2017 نگارش 15.5 ارائه شده و روش فعالسازی آن با نگارش 7.1 آن یکی است (انتخاب گزینهی «C# latest minor version (latest)» در تنظیمات پیشرفتهی Build خواص پروژه). همچنین اگر از VSCode استفاده میکنید، نگارش 1.14 افزونهی #C آن، پشتیبانی کاملی را از C# 7.2 به همراه دارد؛ در اینجا، افزودن خاصیت <LangVersion>latest</LangVersion> به فایل csproj برنامه برای استفادهی از آخرین نگارش کامپایلر نصب شده، کفایت میکند. البته باید دقت داشت کامپایلر C# 7.2 به همراه NET Core SDK 2.1.2. ارائه شدهاست. بنابراین تنها نصب آخرین نگارش افزونهی #C مخصوص VSCode برای کامپایل آن کافی نیست و باید حداقل SDK یاد شده (یا نگارش جدیدتر آن) را هم نصب کنید.
نوعهای جدید <Span<T و <ReadOnlySpan<T در C# 7.2
نوعهای جدید <Span<T و <ReadOnlySpan<T جهت ارائهی ناحیههای اختیاری پیوستهای از حافظه، شبیه به آرایهها تدارک دیده شدهاند و هدف استفادهی از آنها، تولید برنامههای سمت سرور با کارآیی بالا است.
برای کار با این نوعها، هم نیاز به کامپایلر C# 7.2 است و هم نصب بستهی نیوگت System.Memory:
این بسته از .NETStandard 1.0. به بعد را پشتیبانی میکند؛ یعنی با +NET 4.5+ ،Mono 4.6. و +NET Core 1.0. سازگار است.
Spanها و امکان دسترسی به انواع حافظه
Spanها میتوانند به حافظهی مدیریت شده، حافظهی بومی (native) و حافظهی اختصاص داده شدهی در Stack اشاره کنند. به عبارتی Spanها یک لایه انتزاعی، برفراز تمام انواع و اقسام حافظههایی هستند که میتوانند در اختیار توسعه دهندگان NET. باشند.
- البته اکثر توسعه دهندگان دات نت از حافظهی مدیریت شده استفاده میکنند. برای مثال Stack memory تنها از طریق کدهای unsafe و واژهی کلیدی stackalloc قابل تخصیص است. این نوع حافظه بسیار سریع است و همچنین بسیار کوچک؛ کمتر از یک مگابایت که به خوبی در CPU cache جا میشود. اما اگر در این بین حجم حافظهی تخصیصی بیشتر از یک مگابایت شود، بلافاصله استثنای StackOverflowException غیرقابل مدیریتی را به همراه خاتمهی فوری برنامه به همراه خواهد داشت. برای نمونه از این نوع حافظه در جهت مدیریت رخدادهای داخلی corefx زیاد استفاده میشود.
- حافظهی مدیریت شده، همان حافظهای است که توسط واژهی کلیدی new در برنامه، جهت ایجاد اشیاء، تخصیص داده میشود و طول عمر آن تحت مدیریت GC است.
- حافظهی مدیریت نشده یا بومی از دید GC مخفی است و توسط متدهایی مانند Marshal.AllocHGlobal و Marshal.AllocCoTaskMem در اختیار برنامه قرار میگیرند. این حافظه باید به صورت صریحی توسط توسعه دهنده به کمک متدهایی مانند Marshal.FreeHGlobal و Marshal.FreeCoTaskMem آزاد شود. وب سرور Kestrel مخصوص ASP.NET Core، از این روش جهت کار با آرایههای حجیم، جهت کاهش بار GC استفاده میکند.
مزیت کار با Spanها این است که دسترسی امن و type safeایی را به انواع حافظههای مهیا، جهت توسعه دهندگانی که عموما کدهای unsafe ایی را نمینویسند و با اشارهگرها به صورت مستقیم کار نمیکنند، میسر میکند. برای مثال تا پیش از معرفی Spanها، برای دسترسی به 1000 عنصر یک آرایهی 10 هزار عنصری و ارسال آن به یک متد، نیاز بود تا ابتدا یک کپی از این 1000 عنصر را تهیه کرد. این عملیات از لحاظ میزان مصرف حافظه و همچنین زمان انجام آن، بسیار هزینهبر است. با استفاده از <Span<T میتوان یک دید مجازی از آن آرایه را بدون اختصاص آرایهای و یا آرایههایی جدید، ارائه کرد.
مثالی از کاربرد Spanها جهت کاهش تعداد بار تخصیصهای حافظه
برای نمونه، متد IsValidName زیر، بررسی میکند که طول رشتهی دریافتی حداقل 2 باشد و حتما با یک حرف شروع شده باشد:
در این حالت یک نمونه مثال از استفادهی آن میتواند به صورت زیر باشد:
در اینجا زمانیکه از متد Substring استفاده میشود، در حقیقت تخصیص حافظهی دومی جهت تولید firstName رخ میدهد.
همچنین اگر این اطلاعات را از طریق شبکه دریافت کرده باشیم، ممکن است به صورت آرایهای از حروف دریافت شوند:
که به صورت مستقیم در متد IsValidName قابل استفاده نیست و خطای عدم امکان تبدیل []char به string، از طرف کامپایلر صادر میشود:
در این حالت برای استفادهی از این آرایه، نیاز است یک تخصیص حافظهی دیگر نیز صورت گیرد:
اکنون در C# 7.2، بازنویسی این متد توسط ReadOnlySpan، به صورت ذیل است:
که این مزایا را به همراه دارد:
کار با API مربوط به Spanها به همراه تخصیص حافظهی جدیدی نیست. برای نمونه در اینجا متد Slice این API، سبب تخصیص حافظهی جدیدی نمیشود (برخلاف متد Substring) و فقط به قسمتی از حافظهی موجود اشاره میکند (بدون نیاز به کار مستقیم با اشارهگرها و کدهای unsafe).
و یا اینبار امکان استفادهی از آرایهای از کاراکترها، بدون نیاز به تخصیص حافظهای جدید، برای بررسی اعتبار مقادیر دریافتی میسر است:
برای نمونه از یک چنین APIایی در پشت صحنهی کتابخانههایی مانند SignalR و یا Roslyn، برای بالا بردن کارآیی برنامه، با کاهش تعداد بار تخصیصهای حافظهی مورد نیاز، بسیار استفاده شدهاست. برای نمونه در NET Core 2.1.، حجم رشتههای تخصیص داده شدهی در فریم ورکهای وابسته، به این ترتیب به شدت کاهش یافتهاست.
مثالهایی از کار با API نوع Span
امکان ایجاد یک Span از یک array
پس از آن کار با این span همانند کار با آرایههای معمولی است؛ با این تفاوت که این span تنها یک دید مجازی از قسمتی از این آرایه را ارائه میدهد؛ بدون سربار تخصیص حافظهی اضافی و کپی اطلاعات:
در اینجا slicedBytes یک دید مجازی از ایندکس 5 تا 7 آرایهی arr را ارائه میدهد. کار کردن با آن نیز همانند آرایهها، توسط ایندکسها میسر است.
همچنین تغییرات بر روی Span (غیر read only) بر روی آرایهی اصلی نیز تاثیر گذار است. برای مثال در اینجا با تغییر bytes[2]، مقدار arr[2] نیز تغییر میکند.
و یا روش دیگر ایجاد Span استفاده از متد AsSpan است:
همین عملیات را توسط new Span نیز میتوان به صورت سادهتری ارائه داد:
محدودیتهای کار با Spanها
- Span تنها یک نوع stack-only است.
- Spanها در بین تردها به اشتراک گذاشته نمیشوند. هر استک در یک زمان تنها توسط یک ترد قابل دسترسی است. بنابراین Spanها thread-safe هستند.
- طول عمر Spanها کوتاه است و قابلیت قرارگیری بر روی heap با طول عمر بیشتر را ندارند؛ یعنی:
فیلدهای یک کلاس در heap ذخیره میشوند. بنابراین محل ذخیره سازی spanها نیستند.
معرفی نوع <Memory<T
با توجه به محدودیتهای Span و خصوصا اینکه به عنوان پارامتر متدهای async قابل استفاده نیست (چون بر روی stack ذخیره میشوند)، نوع دیگری به نام <Memory<T نیز به همراه C# 7.2 ارائه شدهاست. البته این نوع هنوز به بستهی نیوگت فوق اضافه نشدهاست و به همراه ارائه نهایی NET Core 2.1. ارائه خواهد شد.
این نوع، محدودیت <Span<T را نداشته و قابلیت ذخیره سازی بر روی heap را دارا است.
در اینجا نیز میتوان از یک آرایه، یک <Memory<T را ایجاد و سپس یک <Span<T را از آن دریافت و با Sliceهای آن کار کرد.
نوعهای جدید <Span<T و <ReadOnlySpan<T در C# 7.2
نوعهای جدید <Span<T و <ReadOnlySpan<T جهت ارائهی ناحیههای اختیاری پیوستهای از حافظه، شبیه به آرایهها تدارک دیده شدهاند و هدف استفادهی از آنها، تولید برنامههای سمت سرور با کارآیی بالا است.
برای کار با این نوعها، هم نیاز به کامپایلر C# 7.2 است و هم نصب بستهی نیوگت System.Memory:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.0</TargetFramework> <LangVersion>latest</LangVersion> </PropertyGroup> <ItemGroup> <PackageReference Include="System.Memory" Version="4.4.0-preview1-25305-02" /> </ItemGroup> </Project>
Spanها و امکان دسترسی به انواع حافظه
Spanها میتوانند به حافظهی مدیریت شده، حافظهی بومی (native) و حافظهی اختصاص داده شدهی در Stack اشاره کنند. به عبارتی Spanها یک لایه انتزاعی، برفراز تمام انواع و اقسام حافظههایی هستند که میتوانند در اختیار توسعه دهندگان NET. باشند.
- البته اکثر توسعه دهندگان دات نت از حافظهی مدیریت شده استفاده میکنند. برای مثال Stack memory تنها از طریق کدهای unsafe و واژهی کلیدی stackalloc قابل تخصیص است. این نوع حافظه بسیار سریع است و همچنین بسیار کوچک؛ کمتر از یک مگابایت که به خوبی در CPU cache جا میشود. اما اگر در این بین حجم حافظهی تخصیصی بیشتر از یک مگابایت شود، بلافاصله استثنای StackOverflowException غیرقابل مدیریتی را به همراه خاتمهی فوری برنامه به همراه خواهد داشت. برای نمونه از این نوع حافظه در جهت مدیریت رخدادهای داخلی corefx زیاد استفاده میشود.
- حافظهی مدیریت شده، همان حافظهای است که توسط واژهی کلیدی new در برنامه، جهت ایجاد اشیاء، تخصیص داده میشود و طول عمر آن تحت مدیریت GC است.
- حافظهی مدیریت نشده یا بومی از دید GC مخفی است و توسط متدهایی مانند Marshal.AllocHGlobal و Marshal.AllocCoTaskMem در اختیار برنامه قرار میگیرند. این حافظه باید به صورت صریحی توسط توسعه دهنده به کمک متدهایی مانند Marshal.FreeHGlobal و Marshal.FreeCoTaskMem آزاد شود. وب سرور Kestrel مخصوص ASP.NET Core، از این روش جهت کار با آرایههای حجیم، جهت کاهش بار GC استفاده میکند.
مزیت کار با Spanها این است که دسترسی امن و type safeایی را به انواع حافظههای مهیا، جهت توسعه دهندگانی که عموما کدهای unsafe ایی را نمینویسند و با اشارهگرها به صورت مستقیم کار نمیکنند، میسر میکند. برای مثال تا پیش از معرفی Spanها، برای دسترسی به 1000 عنصر یک آرایهی 10 هزار عنصری و ارسال آن به یک متد، نیاز بود تا ابتدا یک کپی از این 1000 عنصر را تهیه کرد. این عملیات از لحاظ میزان مصرف حافظه و همچنین زمان انجام آن، بسیار هزینهبر است. با استفاده از <Span<T میتوان یک دید مجازی از آن آرایه را بدون اختصاص آرایهای و یا آرایههایی جدید، ارائه کرد.
مثالی از کاربرد Spanها جهت کاهش تعداد بار تخصیصهای حافظه
برای نمونه، متد IsValidName زیر، بررسی میکند که طول رشتهی دریافتی حداقل 2 باشد و حتما با یک حرف شروع شده باشد:
static class NameValidatorUsingString { public static bool IsValidName(string name) { if (name.Length < 2) return false; if (char.IsLetter(name[0])) return true; return false; } }
string fullName = "User 1"; string firstName = fullName.Substring(0, 4); NameValidatorUsingString.IsValidName(firstName);
همچنین اگر این اطلاعات را از طریق شبکه دریافت کرده باشیم، ممکن است به صورت آرایهای از حروف دریافت شوند:
char[] anotherFullName = { 'A', 'B' };
NameValidatorUsingString.IsValidName(anotherFullName);
NameValidatorUsingString.IsValidName(new string(anotherFullName));
اکنون در C# 7.2، بازنویسی این متد توسط ReadOnlySpan، به صورت ذیل است:
static class NameValidatorUsingSpan { public static bool IsValidName(ReadOnlySpan<char> name) { if (name.Length < 2) return false; if (char.IsLetter(name[0])) return true; return false; } }
ReadOnlySpan<char> fullName = "User 1".AsSpan(); ReadOnlySpan<char> firstName = fullName.Slice(0, 4); NameValidatorUsingSpan.IsValidName(firstName);
و یا اینبار امکان استفادهی از آرایهای از کاراکترها، بدون نیاز به تخصیص حافظهای جدید، برای بررسی اعتبار مقادیر دریافتی میسر است:
char[] anotherFullName = { 'A', 'B' }; NameValidatorUsingSpan.IsValidName(anotherFullName);
برای نمونه از یک چنین APIایی در پشت صحنهی کتابخانههایی مانند SignalR و یا Roslyn، برای بالا بردن کارآیی برنامه، با کاهش تعداد بار تخصیصهای حافظهی مورد نیاز، بسیار استفاده شدهاست. برای نمونه در NET Core 2.1.، حجم رشتههای تخصیص داده شدهی در فریم ورکهای وابسته، به این ترتیب به شدت کاهش یافتهاست.
مثالهایی از کار با API نوع Span
امکان ایجاد یک Span از یک array
var arr = new byte[10]; Span<byte> bytes = arr; // Implicit cast from T[] to Span<T>
Span<byte> slicedBytes = bytes.Slice(start: 5, length: 2); slicedBytes[0] = 42; slicedBytes[1] = 43; slicedBytes[2] = 44; // Throws IndexOutOfRangeException bytes[2] = 45; // OK
همچنین تغییرات بر روی Span (غیر read only) بر روی آرایهی اصلی نیز تاثیر گذار است. برای مثال در اینجا با تغییر bytes[2]، مقدار arr[2] نیز تغییر میکند.
و یا روش دیگر ایجاد Span استفاده از متد AsSpan است:
var array = new byte[100]; Span<byte> interiorRef1 = array.AsSpan().Slice(start: 20);
Span<byte> interiorRef2 = new Span<byte>(array: array, start: 20, length: array.Length - 20);
محدودیتهای کار با Spanها
- Span تنها یک نوع stack-only است.
- Spanها در بین تردها به اشتراک گذاشته نمیشوند. هر استک در یک زمان تنها توسط یک ترد قابل دسترسی است. بنابراین Spanها thread-safe هستند.
- طول عمر Spanها کوتاه است و قابلیت قرارگیری بر روی heap با طول عمر بیشتر را ندارند؛ یعنی:
- به صورت فیلد در یک نوع non-stackonly قابل تعریف نیستند:
class Impossible { Span<byte> field; }
- به عنوان پارامترهای متدهای async قابل استفاده نیستند. چون در این بین در پشت صحنه یک AsyncMethodBuilder تشکیل میشود که در قسمتی از آن، پارامترها بر روی heap قرار میگیرند.
- هرجائیکه عملیات boxing صورت گیرد، نتیجهی عملیات بر روی heap قرار میگیرد. بنابراین در یک چنین مواردی نمیتوان از Spanها استفاده کرد. برای مثال تعریف Func<T> valueProvider و سپس فراخوانی ()valueProvider.Invoke به همراه یک boxing است. بنابراین نمیتوان از spanها به عنوان نوع آرگومان جنریک استفاده کرد. این مورد هرچند کامپایل میشود، اما در زمان اجرا سبب خاتمهی برنامه خواهد شد و یا نمونهی دیگر، عدم امکان دسترسی به آنها توسط reflection invoke APIs است که سبب boxing میشود.
معرفی نوع <Memory<T
با توجه به محدودیتهای Span و خصوصا اینکه به عنوان پارامتر متدهای async قابل استفاده نیست (چون بر روی stack ذخیره میشوند)، نوع دیگری به نام <Memory<T نیز به همراه C# 7.2 ارائه شدهاست. البته این نوع هنوز به بستهی نیوگت فوق اضافه نشدهاست و به همراه ارائه نهایی NET Core 2.1. ارائه خواهد شد.
این نوع، محدودیت <Span<T را نداشته و قابلیت ذخیره سازی بر روی heap را دارا است.
static async Task<int> ChecksumReadAsync(Memory<byte> buffer, Stream stream) { int bytesRead = await stream.ReadAsync(buffer); return Checksum(buffer.Span.Slice(0, bytesRead)); // Or buffer.Slice(0, bytesRead).Span }
یکی از امکانات کمتر شناخته شده در دات نت، امکان تولید اتوماتیک کد (Code Generator)، توسط فایلهایی به عنوان Text template میباشد. اگر چه فایلهای Text template با پسوند tt از Visual Studio 2008 بطور آشکار به IDE اضافه گردیدهاند، این امکان پیش از این نیز بصورت توکار در Visual Studio جهت تولید کد دات نت برای ابزارهایی مانند Dataset ، Report و ... وجود داشته است. در حال حاضر Visual Studio بصورت توکار از این امکان برای تولیدکلاسها و کدهای EntityFramework ( edmx ) ،dbml ، Dataset و ... استفاده مینماید.
شما نیز با دانستن قواعد ساده کد نویسی برای Text templateها میتوانید از این امکان برای تولید اتوماتیک کلاسها، HTML ، XML و بطور کلی هر نوع فایل متنی استفاده نمایید. کاربردهای عملی Text template بیشتر برای تولید کد از روی دیتابیس و مثلا بر اساس فیلدهای هر جدول و امثال آن میباشد. اما با کمی خلاقیت استفادههای بسیار زیاد و جالبی را میتوانید از آن مشاهده نمایید.
کاربردهایی مانند : تولید خود کار فایل Config، تولید خودکار Unit Test، تولید خودکار کلاسهای CRUD برای هر موجودیت در لایه Data، تولید خودکار SQL برای StoredProcedure ها، تولید خودکار Html و Js، تولید خودکار فرمهای ASPX و ... برای فرمهای ثابت و تکراری با فرآیند مشخص، تولید خودکار مستندات پروژه در قالب Word Document , … ، تولید خودکار فایلهای Excel از اطلاعات خاص و تولید خودکار فرمهای xaml و .....
در این آموزش با قواعد اصلی نوشتن کد برای Text templateها آشنا میشویم و چند نمونه از کاربردهای آن را به عنوان مثال کاربردی مورد بررسی قرار خواهیم داد.
برای شروع قبل از توضیح در مورد قواعد کد نویسی Text template، یک فایل Text template ایجاد نمایید. برای ایجاد، از پنجره Add New Item یک فایل Text template به پروژه اضافه نمایید:
Language زبانی را مشخص میکند که میخواهید با آن داخل فایل Text template کد نویسی نمایید. تعیین آن برای کامپایل الزامی است.
Extension نیز پسوند فایل خروجی تولید شده را مشخص مینماید .
اگر در ادامه متن Hello dotnettips را بنویسید و فایل را Save کنید، کنار فایل tt مذکور، یک فایل با همان نام و پسوند txt ایجاد خواهد شد که داخل آن نوشته است:
Hello dotnettips
برای ایجاد فایل خروجی همچنین میتوانید روی فایل tt کلیک راست نموده و از منوی باز شده Run Custom Tool را انتخاب نمایید. توجه داشته باشید که در تنظیمات Custom Tool باید مقدار TextTemplatingFileGenerator وجود داشته باشد:
شما نیز با دانستن قواعد ساده کد نویسی برای Text templateها میتوانید از این امکان برای تولید اتوماتیک کلاسها، HTML ، XML و بطور کلی هر نوع فایل متنی استفاده نمایید. کاربردهای عملی Text template بیشتر برای تولید کد از روی دیتابیس و مثلا بر اساس فیلدهای هر جدول و امثال آن میباشد. اما با کمی خلاقیت استفادههای بسیار زیاد و جالبی را میتوانید از آن مشاهده نمایید.
کاربردهایی مانند : تولید خود کار فایل Config، تولید خودکار Unit Test، تولید خودکار کلاسهای CRUD برای هر موجودیت در لایه Data، تولید خودکار SQL برای StoredProcedure ها، تولید خودکار Html و Js، تولید خودکار فرمهای ASPX و ... برای فرمهای ثابت و تکراری با فرآیند مشخص، تولید خودکار مستندات پروژه در قالب Word Document , … ، تولید خودکار فایلهای Excel از اطلاعات خاص و تولید خودکار فرمهای xaml و .....
در این آموزش با قواعد اصلی نوشتن کد برای Text templateها آشنا میشویم و چند نمونه از کاربردهای آن را به عنوان مثال کاربردی مورد بررسی قرار خواهیم داد.
برای شروع قبل از توضیح در مورد قواعد کد نویسی Text template، یک فایل Text template ایجاد نمایید. برای ایجاد، از پنجره Add New Item یک فایل Text template به پروژه اضافه نمایید:
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ output extension=".txt" #>
Extension نیز پسوند فایل خروجی تولید شده را مشخص مینماید .
اگر در ادامه متن Hello dotnettips را بنویسید و فایل را Save کنید، کنار فایل tt مذکور، یک فایل با همان نام و پسوند txt ایجاد خواهد شد که داخل آن نوشته است:
Hello dotnettips
برای ایجاد فایل خروجی همچنین میتوانید روی فایل tt کلیک راست نموده و از منوی باز شده Run Custom Tool را انتخاب نمایید. توجه داشته باشید که در تنظیمات Custom Tool باید مقدار TextTemplatingFileGenerator وجود داشته باشد:
خوب؛ برای ادامه، باید با قواعد کد نویسی در Text template آشنا شوید. جلسه بعدی قواعد کد نویسی T4 را بررسی خواهیم کرد.