نوشتن کدی که کد می‌نویسد!
1398/03/09 10:29 , میلاد صاحب نظر

نوشتن کدی که کد می‌نویسد!

تکنولوژی T4 مایکروسافت کاری کرده است که نوشتن برنامه‌هایی که، خب، برنامه‌های دیگر را می‌نویسند امکان پذیر و بسیار آسان شود! شما به قالب می‌گویید که چگونه کدهای خسته‌کننده را بنویسد و برنامه‌ هم با کمال میل کد را می‌نویسد و کارهای لازم را برای آن انجام می‌دهد.

وقتی روی یک پروژه اپلیکیشن موبایل کار می‌کردم، نیاز مبرمی به مکانیزه کردن فرآیند تولید و نگهداری کد cookie-cutter مورد نیاز هر صفحه از اپلیکیشن داشتم. بنابراین شروع به جستجو برای روش‌های انجام مکانیزه سازی کردم.

اولین گزینه‌ای که یافتم یک تکنولوژی متعلق به مایکروسافت به نام CodeDOM بود. این API روشی برای تولید کلاس‌ها و اعضای آن‌ها فراهم می‌کند. برای مثال، کد تولید کننده برای اضافه کردن یک فیلد Private double به نام widthValue به یک کلاس موجود، چیزی شبیه به کد زیر است:

CodeMemberField widthValueField = new CodeMemberField();
widthValueField.Attributes = MemberAttributes.Private;
widthValueField.Name = "widthValue";
widthValueField.Type = new CodeTypeReference(typeof(System.Double));
widthValueField.Comments.Add(
   new CodeCommentStatement("The width of the object."));
targetClass.Members.Add(widthValueField);

همان‌طور که مشاهده می‌کنید، کد خیلی سر راست و ساده‌ای است، اما همچنین طولانی و عجیب است. برای تولید پروژه کلاس استاندارد به میزان زیادی کد نیاز است. من راه حلی نمی‌خواستم که بیشتر از حل معمولی مشکلم زمان‌بر باشد!

خوشبختانه یک تکنولوژی بهتر هم وجود داشت: قالب‌های T4. تکنولوژی T4 مخفف عبارت “Text Template Transformation Toolkit” (جعبه ابزار تبدیل قالب متن) است. این تکنولوژی از سال ۲۰۰۵ در دسترس عموم قرار گرفت و اولین بار همراه با انتشار نسخه ۲۰۰۸ ویژوال استودیو ارائه شد.

از آن زمان، این تکنولوژی به روز رسانی شده، عملکرد آن بهبود یافته است و با ابزارهای DSL ویژوال استودیو بهتر می‌تواند تعامل داشته باشد.

مایکروسافت خودش در خفا از T4 برای تولید کد در تکنولوژی‌هایی مانند ASP.NET MVC view/controller generation، ADO.NET Entity Framework و ASP.NET Dynamic Data استفاده می‌کند.

T4 در عمل

کد زیر یک مثال ساده همانند Hello World برای قالب T4 است.

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
 
<#@ import namespace="System.Collections.Generic" #>
<# 
var Friends = new List<string>();
// Code here may retrieve friend names from the database and 
// put them into a friends array 
// For this example, we'll just add a few ourselves:
Friends.AddRange(new string[] {"Brad","Dan","Mike","Wayne","Mark"});
#>
using System;
 
class HelloFriends {
<#  foreach (var f in Friends) { #>
  public void Hello<#= f #>() {
     Console.WriteLine("Hello there, <#= f #>, my friend!");
  }
 
<# } #>
}

اگر تا به حال Java Server Pages، classic Active Server Pages، ASP.NET MVC views یا تکنولوژی‌های مشابه را دیده باشید، پس ممکن است این نوع کد برای شما آشنا باشد.

چیزی که مشاهده می‌کنید دو سطح کد است – کد قالب و کد خروجی. کد قالب زمانی که قالب پردازش می‌شود، اجرا خواهد شد. این اتفاق هر دفعه که قالب تغییر کرده و save می‌شود پیش می‌آید. (همچنین می‌توان کاری کرد که هر موقع اپلیکیشن کامپایل می‌شود نیز اجرا شود). بنابراین کد قالب در زمان طراحی اجرا می‌شود تا کد خروجی را تولید کند.

سپس کد خروجی در رانتایم اجرا می‌شود.

در این مورد کد خروجی چیست؟ خوشحالم که پرسیدید...

using System;
 
class HelloFriends {
  public void HelloBrad() {
     Console.WriteLine("Hello there, Brad, my friend!");
  }
 
  public void HelloDan() {
     Console.WriteLine("Hello there, Dan, my friend!");
  }
 
  public void HelloMike() {
     Console.WriteLine("Hello there, Mike, my friend!");
  }
 
  public void HelloWayne() {
     Console.WriteLine("Hello there, Wayne, my friend!");
  }
 
  public void HelloMark() {
     Console.WriteLine("Hello there, Mark, my friend!");
  }
 
}

کد قالب، که گاهی کد کنترل نیز نامیده می‌شود، همیشه درون دستورالعمل‌های <#and#> قرار دارد و همیشه در زمان طراحی اجرا می‌شود. وقتی اجرا شد، فایل خروجی را تولید می‌کند.

تشریح T4

دو خط اول قالب معمولاً خیلی شبیه به دو خط کد زیر هستند:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>

توجه کنید که این خطوط کد که دارای @#> است، نشان دهنده این است که دستورالعمل هستند. یک دستورالعمل، اطلاعاتی در مورد چگونگی پردازش قالب فراهم می‌کند.

در اولین خط، چند اتریبیوت قرار دارند که مهم‌ترین آن‌ها language است. این اتریبیوت زبانی که برای کد قالب استفاده شده است را مشخص می‌کند. توجه کنید که این زبان با زبان مورد استفاده برای خروجی می‌تواند متفاوت باشد. در نتیجه، برای مثال اگر بخواهید می‌توانید از یک قالب C# برای تولید کد خروجی VB استفاده کنید.

افزونه مورد استفاده برای فایل خروجی در خط دوم مشخص شده است. بنابراین در این مورد، از یک قالب C# برای تولید خروجی C# استفاده کرده‌ایم.

سومین خط نیز یک دستورالعمل است.

<#@ import namespace="System.Collections.Generic" #>

دستورالعمل import یک namespace مشخص می‌کند که شما می‌خواهید از آن در کد قالبتان استفاده کنید، مثلاً یک Imports در VB یا یک using در C#. به یاد داشته باشید که این دستورالعمل فقط برای کد قالب است، نه برای کد خروجی. می‌توانید هر تعداد از این خطوط کد که می‌خواهید داشته باشید.

کد قالب گاهی به عنوان کد کنترل نیز شناخته می‌شود. در بخش بعدی در مورد همین صحبت می‌کنیم.

<# 
var Friends = new List<string>();
// Code here may retrieve friend names from the database and 
// put them into a friends array 
// For this example, we'll just add a few ourselves:
Friends.AddRange(new string[] {"Brad","Dan","Mike","Wayne","Mark"});
#>

معمولاً یک بلوک بزرگ از کد کنترل در بالای قالب شما وجود دارد و معمولاً داده‌های مورد استفاده برای تولید این قالب از همین‌جا به دست می‌آیند. یک قالب در واقع یک روش ایجاد پویای کد است، بنابراین باید از داده‌های پویا استفاده کند. آن داده می‌تواند از یک پایگاه داده، یک فایل XML یا عملاً هر منبع داده دیگری به دست آید.

اما هر چه که باشد، احتمالاً باید کمی تمیزکاری انجام دهید تا بتوانید به آن دسترسی یابید و سپس داده‌ای که می‌توان در یک آرایه، لیست، دایره لغات یا چند ساختمان داده داخلی دیگر استفاده کرد را به دست آورید. در این بلوک تمام این کارها باید انجام شود.

همان‌طور که در کامنت‌ها مشخص است من در اینجا کمی تقلب کردم تا کار ساده‌تر شود. من یک آرایه رشته را با نام چند نفر از دوستانم پر کردم.

بخش بعدی در خارج از حائل‌های <#and#> قرار دارد.

#>
using System;
 
class HelloFriends {
<#

چیزهایی که در خارج از حائل‌ها قرار دارند بلوک‌های متن یا text blocks نامیده می‌شوند. بلوک‌های متن به زبان ساده قطعاتی هستند که دقیقاً به همان شکلی که هستند در فایل خروجی کپی می‌شوند. در اینجا، فایل خروجی با یک عبارت using شروع می‌شود و سپس اولین خط از یک تعریف کلاس قرار می‌گیرد.

توجه کنید که این کد using برای فایل خروجی استفاده می‌شود، بر خلاف  …import namespace@#> که در بالا گفته شد (این کد برای کد قالب کاربرد داشت).

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

<#  foreach (var f in Friends) { #>
  public void Hello<#= f #>() {
     Console.WriteLine("Hello there, <#= f #>, my friend!");
  }
 
<# } #>
}

حلقه foreach درون حائل‌ها قرار دارد، بنابراین در زمان طراحی برای تمام عناصر موجود در لیست Friends حلقه را اجرا می‌کند. توجه کنید که <#{#> در نزدیکی انتهای کد، در واقع انتهای حلقه است. اکثر چیزهایی که درون حلقه قرار دارند متن خروجی هستند که یک تعریف متد برای هر دوست ایجاد می‌کنند.

به هر حال دو حائل خاص درون این متن به کار رفته‌اند: یعنی <#and=#>. به این‌ها بلوک‌های کنترل عبارت گفته می‌شود. آن‌ها شامل کد برای اجرا نیستند، اما در عوض شامل یک عبارت هستند که باید ارزیابی شود. عبارت به یک مقدار تنها خلاصه می‌شود که جایگزین بلوک عبارت در خروجی نهایی می‌شود.

در هر دو موارد در اینجا، آن عبارت همان رشته موجود است – یعنی نام دوست. این کار خروجی زیر را برای اولین عنصر لیست (یعنی Brad) تولید می‌کند.

 public void HelloBrad() {
     Console.WriteLine("Hello there, Brad, my friend!");
  }

حقه‌های کار

قالب‌های T4 در تئوری و مفهوم خیلی ساده و سر راست هستند. اما در عمل، گاهی ممکن است شرایط پیچیده و گیج کننده شود. هر چه باشد، وقتی به باگ‌ها برمی‌خورید، ممکن است باگ‌های درون کد قالب یا باگ‌های درون کد خروجی باشند. بنابراین باید هر دو قطعه کد را در آن واحد دیباگ کنید.

در ادامه چند حقه و نکته برای ساده‌تر کردن توسعه T4 ارائه خواهیم داد.

اضافه کردن یک قالب

می‌توانید یک قالب T4 به هر پروژه‌ای اضافه کنید. وقتی می‌خواهید یک آیتم دیالوگ جدید اضافه کنید، ممکن است یک گزینه برای قالب متن ببینید (شاید هم نبینید). اگر دیدید، احتمالاً این شکلی است:

اضافه کردن آیتم جدید

اضافه کردن آیتم جدید

اگر ندیدید، نگران نباشید – می‌توانید خیلی راحت فایل متن را انتخاب کنید و سپس بعد از اینکه فایل ایجاد شد، نام آن را با پسوند tt. بازنویسی کنید. در جواب دیالوگ سؤال are you sure جواب yes بدهید تا یک قالب T4 برای شما ایجاد شود.

سنگ اول را درست بگذار

اولین قدم برای یک قالب جدید این است که خطوط اول را اصلاح کنید، یا اگر با یک قالب خالی شروع کرده‌اید، خطوط اول را وارد کنید:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>

زبان قالب و افزونه فایل خروجی را مشخص کنید. توجه کنید که می‌توانید فایل خروجی را با هر پسوندی تولید کنید، نه فقط کد. می‌توانید یک فایل XML، یک فایل متنی یا تقریباً هر چیز دیگری تولید کنید.

قالب و فایل خروجی خود را سازماندهی کنید

ویژوال استودیو برای راحتی کار، صفحه خروجی را در زیر قالب در قسمت Solution Explorer قرار می‌دهد.

Solution Explorer

Solution Explorer

در هنگام توسعه دادن یک قالب، بهترین روشی که پیدا کردم تا ببینم چه اتفاقی می‌افتد، این است که از یک صفحه مجزای عمودی در ویژوال استودیو با یک قالب در سمت چپ و فایل خروجی در سمت راست استفاده کنم.

صفحه مجزای عمودی در ویژوال استودیو

صفحه مجزای عمودی در ویژوال استودیو

همین‌طور که قالب را اصلاح می‌کنید، می‌توانید هر موقع که خواستید save کنید و وقتی کردید، قالب مجدداً run می‌شود و خروجی متناظر آن در سمت راست ظاهر می‌شود.

در تعقیب باگ‌ها

وقتی گفتم باید قالب و خرجی را به صورت هم‌زمان دیباگ کنید، شوخی نمی‌کردم. فرض کنید فراموش کردید که در انتهای خط AddRabge در قالب Friends سمی کالن (;) بگذارید. چیزی که مشاهده خواهید کرد این است:

لیست ارور

لیست ارور

اروری که انتظار دارید را دریافت می‌کنید، اما علاوه بر آن چند ارور گیج کننده دیگر نیز دریافت خواهید کرد. علاوه بر این، خواهید دید که فایل خروجی به این شکل است:

فایل خروجی

فایل خروجی

اگر اجرای کد قالب موفقیت آمیز نباشد، گاهی قالب اصلاً نمی‌تواند تولید شود. به خصوص اگر این شکست در اجرا، در اولین بخش تمیزکاری/جمع‌آوری داده اتفاق بیفتد. در این مورد، یک خط کد همانند چیزی که در اینجا می‌بینید به دست خواهید آورد. توجه کنید که سومین ارور یک ارور Friends.cs است.

علی رغم شکست اجرای قالب، کامپایلر هنوز هم سعی می‌کند فایل خروجی را پردازش کرده و آن یک خط را پیدا کند، بنابراین ارور شماره ۳ پیش می‌آید. هر دفعه که اجرای قالب قبل از تولید کردن چیزی با شکست مواجه شود، این ارور را خواهید دید.

اما این فقط ساده‌ترین مورد ممکن است. اگر در یک قطعه کد یا کدهای دیگری که با خروجی قاطی شده‌اند ارور داشته باشید ممکن است ارورهای syntax یا ارورهای دیگر در خروجی مشاهده کنید. همیشه روی اولین ارورهایی که در قالب به وجود می‌آیند تمرکز کنید.

وقتی آن ارورها را برطرف کردید، گاهی ارورهای خروجی نیز رفع می‌شوند.

ویراستار کد خود را به روز رسانی کنید

ممکن است توجه کرده باشید که پشتیبانی ویراستار کد ویژوال استودیو برای T4 یک پشتیبانی کامل و شامل نیست. حتی بعد از چهار بار انتشار این تکنولوژی، باز هم T4 هنوز آن پشتیبانی که مستحقش است را به دست نیاورده است. خوشبختانه افزونه‌های سوم شخص رایگانی وجود دارند که می‌توانند این جای خالی را پر کنند.

من از ویراستار T4 رایگانی به نام Tangible استفاده می‌کنم. این ویراستار یک سیستم کد نویسی رنگی بسیار مفید، قابلیت هایلایت کردن، سیستم بررسی syntax قوی و ویژگی‌های مفید دیگری برای کاربر فراهم می‌کند.

ویراستار T4 رایگان Tangible

ویراستار T4 رایگان Tangible

یک مورد دیگر هم هست که هنوز آن را ارزیابی نکرده‌ام، اما یک نام بزرگ دیگر در بین ویراستارهای T4 و دیگر افزونه‌ها، Devart است.

تولید در زمان کامپایل

همان‌طور که مشاهده کردید، قالب‌ها هر دفعه که یک تغییر ایجاد می‌کنید و قالب را Save می‌کنید، مجدداً run می‌شوند. اما تا وقتی منبع داده‌ای که قالب را اجرا می‌کند پویا است، می‌توانید در انتها بخواهید که یک regen در زمان کامپایل انجام دهید. به دلایلی، این نیاز ساده و معمول در پکیج T4 گنجانده نشده است.

اما خوشبختانه، برای یافتن روش‌های انجام آن لازم نیست زیاد جستجو کنید.

ویراستار T4 رایگان Tangible که در قسمت قبلی به آن اشاره کردم یک ویژگی برای هر فایل قالب فراهم می‌کند که TransformOnBuild نام دارد. متأسفانه این ویژگی فقط در صورتی در دسترس است که نسخه Pro نرم‌افزار را خریداری کنید (که ویژگی‌های خیلی زیاد دیگری هم به همراه خواهد داشت).

اما برای این مشکل، لازم نیست هزینه پرداخت کنید.

کافی است در گوگل جستجو کنید تا راه‌حل‌هایی را بیابید که بدون نیاز به یک افزونه که شامل فرآیند اصلاح کد شما باشد و بدون نیاز به افزونه‌ای که بتواند کدهای فایل batch که در پروژه شما وجود دارند را اصلاح کند، بتوانید از آن راه حل‌ها استفاده کنید.

اگر همانند من، شما نیز به دنبال یک راه حل هستید که راحت مشکل شما را حل کند و نیاز به زحمت زیادی نداشته باشد، بد نیست پکیج رایگان و متن باز Clarius TransformOnBuild NuGet را نیز بررسی کنید. برای من که عالی عمل کرد.

یا، اگر دوست دارید، گزینه‌های خیلی زیاد دیگری هم وجود دارند که می‌توانید با جستجو در گوگل آن‌ها را بیابید.

نتیجه

فرآیند تولید کد ممکن است در ابتدا یک امر بعید و ترسناک به نظر برسد. این مبحث، عملاً و به معنای واقعی کلمه یک مبحث برنامه‌نویسی پیشرفته است. به هر حال، مایکروسافت توانسته است سطح پیشرفته آن را به اندازه‌ای پایین بیاورد که بتواند نیازهای ساده کاربران را برطرف کرده و پروژه‌های پیچیده آن‌ها را قابل مدیریت کند.

در این مقاله، شما یک توضیح دقیق و کامل از یک مثال ساده و چند مثال و حقه مفید برای یادگیری آسان این تکنولوژی عالی و هیجان‌انگیز را مشاهده کردید!

منبع: developer

 مطالب مرتبط

 مقدمه ای بر زبان برنامه نویسی #C و پلتفرم NET Framework.
7 دلیل منطقی برای آموختن #C
 طبقه بندی زبان های برنامه نویسی
به دست آوردن Exceptionها در #C و یافتن همه خطاها
 LINQ(زبان جستجوی یکپارچه)
برنامه نویسی شیءگرا چیست؟

از آخرین دوره های آموزشی و تخفیف ها مطلع شوید

با تکمیل فرم زیر ، از اخبار و اطلاعات به روز برنامه نویسی و تکنولوژی عقب نمانید

آخرین مطالب

آموزش جامع SQL Server (جلسه ۱۲)
آموزش جامع SQL Server (جلسه ۱۲)

دستور UPDATE در SQL Server برای تغییر داده‌های موجود در یک جدول، از دستور UPDATE به شکل زیر استفاده ...

آموزش جامع SQL Server (جلسه ۱۵)
آموزش جامع SQL Server (جلسه ۱۵)

دستور DROP TABLE در SQL Server گاهی، لازم است یک جدول که دیگر استفاده‌ای ندارد را حذف کنید. برای ...

آموزش جامع SQL Server (جلسه ۳۵: Window Functionها – بخش ۲)
آموزش جامع SQL Server (جلسه ۳۵: Window Functionها – بخش ۲)

بخش اول از آخرین مبحث دوره جامع آموزش SQL Server در جلسه قبلی بررسی شد. این مبحث که ...

آخرین دیدگاه ها

دیدگاه خود را درباره این پست بنویسید

فرم ارسال نظرات