سایت SeeC
البته فقط برای یک سری زبان خاص این فایلهای منبع تهیه شدهاند.
کتاب Visual Studio 2013
سایت Go by Example
خلاص شدن از شر deep null check
Tools -> Code Snippets Manager (Ctrl+K,Ctrl+B)
در ویژوال استودیو 2010 دو نوع snippet وجود دارد :
1- Expansion snippets : که در محل کرسر (Cursor) اضافه میشوند . مثل cw و enum که به ترتیب دستور writeLine و ساختار یک enum را ایجاد میکنند .
2- SurroundsWith snippets : که میتوانند یک تکه کد انتخاب شده را در بر بگیرند مثل for و یا do که کد انتخاب شده را در یک حلقه for و do-while محصور میکنند .
نکته ای که باید توجه داشت این است که یک snippet میتواند از هر دو نوع باشد . برای مثال for و do و یا if ، در صورتی که کدی انتخاب شده باشد آن را محصور میکنند و گرنه ساختار خالی مرتبط را در محل cursor اضافه میکنند .
همانطور که در ابتدا هم ذکر شد ، علاوه بر snippetهای آمادهی موجود ، توسعه دهنده میتواند قطعه کدهایی را خود ایجاد کرده و مورد استفاده قرار دهد .
در اینجا یک expansion snippet خواهیم ساخت تا کار اضافه کردن بلاک try-catch-finally را برای ما انجام دهد .
- ابتدا یک فایل xml به پروژه اضافه میکنیم و آنرا TryCatchFinally.snippet مینامیم . توجه کنید که نام فایل باید به .snippet ختم شود .
- فایل را باز و درون آن راست کلیک کرده و گزینه Insert snippet > Snippet را انتخاب میکنیم . با اینکار یک قالب پایه snippet ( که یک ساختار xml ) است به فایل اضافه میشود . هر فایل snippet از دو بخش اصلی header و snippet تشکیل شده که بخش header اطلاعاتی کلی درباره قطعه کد را نگهداری میکند و بخش snippet مربوط به تعریف محتوای قطعه کد است .
<codesnippet format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <header> <title>title</title> <author>author</author> <shortcut>shortcut</shortcut> <description>description</description> <snippettypes> <snippettype>SurroundsWith</snippettype> <snippettype>Expansion</snippettype> </snippettypes> </header> <snippet> <declarations> <literal> <id>name</id> <default>value</default> </literal> </declarations> <code language="XML"> <!--[CDATA[<test--> <name>$name$</name> $selected$ $end$]]> </code> </snippet> </codesnippet>
- قالب پیش فرض شامل هر دو نوع snippet است .
<codesnippet format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <header> ... <snippettypes> <snippettype>SurroundsWith</snippettype> <snippettype>Expansion</snippettype> </snippettypes> </header> ... </codesnippet>
از آنجا که قصد داریم یک Expansion snippet بسازیم پس تگ SurroundsWith را حذف میکنیم .
<snippettypes> <snippettype>Expansion</snippettype> </snippettypes>
- در بخش header مقدار تگ Title را به “Try Catch Finally”و مقدار تگ Shortcut را به “trycf” و Description را به “Adds a try-catch-finally block ” تغییر میدهیم . Title عنوان snippet است و وجود آن ضروری است . اضافه کردن shortcut اختیاری است و به عنوان یک متن میانبر برای اضافه کردن snippet استفاده میشود .
<Header> <Title>Try Catch Finally</Title> <Author>mohsen.d</Author> <Shortcut>trycf</Shortcut> <Description>Adds a try-catch-finally block</Description>
- تگ Literal برای تعریف جایگزین برای بخشی از کد درون snippet که احتمال دارد پس از اضافه شدن ، توسط برنامه نویس و یا در صورت استفاده از function توسط خود ویژوال استودیو تغییر کند استفاده میشود . در قطعه کد try-catch-finally ، ما میخواهیم به کاربر اجازه بدهیم که نوع استثنائی را که catch میشود تغییر دهد .
تگ id نامی برای بخش قابل ویرایش تعریف میکند ( که از آن در ادامه در تعریف خود قطعه کد استفاده میکنیم ) . آنرا به “ExceptionName” تغییر میدهیم . تگ default هم مقدار پیش فرضی را برای آن بخش مشخص میکند . ما میخواهیم تمام استثناها را Catch کنیم پس مقدار پیش فرض را برابر "Exception" قرار میدهیم .
..... <declarations> <literal> <id>ExceptionName</id> <default>Exception</default> </literal> </declarations> ...
- و در تگ Code ، خود قطعه کدی که ویژوال استودیو باید آن را اضافه کند ، تعریف میشود . مقدار مشخصه Language آن را به CSharp تغییر میدهیم و محتویات داخل آنرا به شکل زیر اضافه میکنیم .
<code language="CSharp"> <!--[CDATA[ try { $end$ } catch($ExceptionName$) { } finally { } ]]--> </code>
به نحوه استفاده از ExceptionName که در قسمت Literal تعریف کردیم توجه کنید . عبارت $end$ هم یک کلمه رزرو شده است که محل قرار گرفتن cursor را بعد از اضافه شدن قطعه کد مشخص میکند .
- در نهایت snippet ما به شکل زیر خواهد بود :
<codesnippet format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <header> <title>Try Catch Finally</title> <author>mohsen.d</author> <shortcut>trycf</shortcut> <description>Adds a try-catch-finally block</description> <snippettypes> <snippettype>Expansion</snippettype> </snippettypes> </header> <snippet> <declarations> <literal> <id>ExceptionName</id> <default>Exception</default> </literal> </declarations> <code language="CSharp"> <!--[CDATA[ try { $end$ } catch($ExceptionName$) { } finally { } ]]--> </code> </snippet> </codesnippet>
اضافه کردن snippet ساخته شده به visual studio
دو راه برای اضافه کردن snippet تعریف شده به ویژوال استودیو وجود دارد :
روش اول قرار دادن فایل .snippet در پوشه code snippets ویژوال استودیو است که مسیر پیش فرض آن
C:\Users\<UserName>\Documents\Visual Studio 2010\Code Snippets\
گزینه دوم import کردن فایل .snippet به داخل ویژوال استودیو است . در ویژوال استودیو به مسیر
Tools -> Code Snippets Manager (Ctrl+K,Ctrl+B)
استفاده از snippet ساخته شده
برای استفاده از snippet میتوانیم متن میانبر تعریف شده را تایپ کنیم و با دو بار فشردن کلید tab قطعه کد تعریف شده به محل کرسر اضافه میشودهمینطور با فشردن کلیدهای Ctrl+K و Ctrl+X به صورت پشت سر هم منوی “Insert Snippet” ظاهر میشود که از طریق آن میتوانیم Snippet موردنظر را یافته ( بدنبال Title تعریف شده برای snippet در پوشه ای که آنرا ذخیره کرده اید بگردید ) و با انتخاب آن کد تعریف شده اضافه خواهد شد .
برای آشنایی با روشهای مختلف دسترسی به snippetها اینجا را بررسی کنید .
ابزارها
در این پروژه هم مجموعه snippetهای موجود ویژوال استودیو 2010 برای زبان سی شارپ ، جهت سازگاری با stylecop ویرایش و refactor شده اند ( در کنار تعریف snippetهای دیگر ).
public class Form { public string Name { get; set; } public string Title { get; set; } public List<BaseElement> Elements { get; set; } } public abstract class BaseElement { public string Name { get; set; } public string Title { get; set; } } public class Section : BaseElement { public List<TextBox> Elements { get; set; } } public class TextBox : BaseElement { public string Value { get; set; } public string CssClass { get; set; } }
public class FormBuilderController : Controller { // // GET: /FormBuilder/ public ActionResult Index() { var form = new Form(); var section = new Section() { Title = "Basic Info", Name = "section01" }; section.Elements.Add(new TextBox() { Name = "txt1", Title = "First Text Box" }); form.Elements.Add(new TextBox() { Name = "txt1", Title = "Second Text Box" }); var formJson=JsonConvert.SerializeObject(form); return View(formJson); } }
<script type="text/ng-template" id="ElementTemplate"> <div ng-if="control.Type == 'JbSection'"> <h2>{{control.Title}}</h2> <ul> <li ng-repeat="control in control.Elements" ng-include="'ElementTemplate'"></li> </ul> </div> </script>
<script type="text/ng-template" id="element.html"> {{data.label}} <ul> <li ng-repeat="element in data.elements" ng-include="'element.html'"></li> </ul> </script> <ul ng-controller="NestedFormCtrl"> <li ng-repeat="field in formData" ng-include="'element.html'"></li> </ul>
- نصب ماژول
- فعال سازی ماژول
نکته ای که در مورد ماژولهای native وجود دارد این هست که این ماژولها دسترسی بدون محدودیتی به منابع سروری دارند و از این رو حتما باید این نکته را دقت کنید که ماژول native شما از یک منبع مورد اعتماد دریافت شده باشد.
نصب یک native module
- ویرایش دستی فایل کانفیگ و از نسخه IIS7.5 به بعد هم میتوانید از configuration editor هم استفاده کنید.
- استفاده از محیط گرافیکی IIS
- استفاده از خط فرمان با دستور Appcmd
%windir%\system32\inetsrv\config\applicationhost.config
کسی که نیاز به دسترسی به این مسیر و انجام تغییرات دارد باید در بالاترین سطح مدیریتی سرور باشد.
<globalModules> <addname="DefaultDocumentModule"image="%windir%\system32\inetsrv\defdoc.dll"/> <addname="DirectoryListingModule"image="%windir%\system32\inetsrv\dirlist.dll"/> <add name="StaticFileModule"image="%windir%\system32\inetsrv\static.dll"/> ... </globalModules>
<add name="ManagedEngine64" image="%windir%\Microsoft.NET\Framework64\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness64" /> <add name="ManagedEngine" image="%windir%\Microsoft.NET\Framework\v2.0.50727\webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" /> <add name="ManagedEngineV4.0_32bit" image="%windir%\Microsoft.NET\Framework\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" /> <add name="ManagedEngineV4.0_64bit" image="%windir%\Microsoft.NET\Framework64\v4.0.30319\webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness64" />
<modules runAllManagedModulesForAllRequests="true"/>
شکل زیر هم نمونه ای حالت مجتمع هست:
در کل امروزه دیگر استفاده از روش کلاسیک راهکار درستی نیست و این ویژگی تنها به عنوان یک سازگاری با نمونه کارهای قدیمی است.
- ISAPI filters
- globalModules
- handlers
- modules
عناصر داخلی تابع
در داخل هر تابع دو شیء خاص به نامهای arguments و this وجود دارند. شیء arguments ، که قبلا در مورد آن صحبت کردیم، دارای یک ویژگی به نام callee میباشد که به تابعی اشاره میکند که arguments متعلق به آن است. به مثال زیر توجه کنید که تابع فاکتوریل را به صورت بازگشتی پیاده سازی نموده است:
function factorial(num) { if (num <= 1) return 1; else return num * factorial(num - 1); }
function factorial(num) { if (num <= 1) return 1; else return num * arguments.callee(num - 1); }
function factorial(num) { if (num <= 1) return 1; else return num * arguments.callee(num - 1); } var anotherFactorial = factorial; factorial = function() { return 0; } alert(anotherFactorial(5)); alert(factorial(5));
خروجی :
120
0
در مثال فوق، ابتدا تابع factorial تعریف شده و سپس به متغیر anotherFactorial نسبت داده شدهاست. سپس تابع factorial با تعریف جدیدی جایگزین شده که مقدار 0 بر میگرداند. همانطور که مشاهده میکنید، تابع بازگشتی از طریق arguments.callee فراخوانی گردیده است. اما اگر به جای arguments.callee از نام تابع، یعنی factorial استفاده کرده بودیم، خروجی در هر دو مرحله 0 میبود. زیرا anotherFactorial نیز، در داخل خود، تابع factorial جایگزین شده با خروجی 0 را فراخوانی مینمود.
شیء دیگری که در توابع وجود دارد، شی this میباشد. این شیء به شیء ای اشاره میکند که تابع، متعلق به آن است یا برای آن فعالیت میکند. اگر تابعی به صورت عمومی تعریف شود، متعلق به شیء window میباشد. بنابراین this در این توابع به شیء window اشاره میکند. به مثال زیر توجه کنید:
window.color = "red"; var o = { color: "blue" }; o.showColor = sayColor; function sayColor() { alert(this.color); } sayColor(); o.showColor();
خروجی :
"red"
"blue"
ابتدا ویژگی color را برای شیء window تعریف کردیم. سپس شیء ای به نام o ایجاد نمودیم که دارای ویژگی color میباشد. همچنین تابعی به نام showColor را برای آن تعریف نمودیم که تابع sayColor به آن نسبت داده شده است. در تابع sayColor نیز مقدار ویژگی color را به صورت پیغامی نمایش میدهیم. زمانی که این تابع را فراخوانی مینماییم، شیء this موجود در آن به شیء window اشاره میکند؛ بنابراین مقدار "red" را نمایش میدهد. سپس تابع showColor از شیء o را فراخوانی نمودیم که شیء this در آن به شیء o اشاره میکند. زیرا تابع showColor که به تابع sayColor اشاره میکند، متعلق به شیء o میباشد.
ویژگیها و توابع اشیاء ایجاد شده از Function
ویژگی caller
یکی از ویژگیهای توابع که میتواند مورد استفاده قرار بگیرد، ویژگی caller میباشد. این ویژگی مشخص میکند که چه تابعی، تابع جاری را فراخوانی نموده است. اگر فراخوانی تابع جاری در حوزهی عمومی (Global Scope) صورت گرفته باشد، این ویژگی مقدار null بر میگرداند؛ در غیر اینصورت محتوای تابع فراخواننده برگردانده خواهد شد.
function outer() { inner(); } function inner() { alert(inner.caller); } inner(); outer();
خروجی :
null function outer() { inner(); }
ویژگی length
ویژگی دیگری که برای توابع مورد استفاده قرار میگیرد، ویژگی length میباشد. این ویژگی تعداد Named Arguments (پارامترهای نامی) تابع را بر میگرداند.
function sayName(name) { alert(name); } function sum(num1,num2) { return num1 + num2; } function sayHi() { alert("Hi"); } alert(sayName.length); alert(sum.length); alert(sayHi.length);
خروجی :
1
2
0
همانطور که در خروجی نیز مشاهده میکنید، تعداد آرگومانهای هر یک از توابع تعریف شده نمایش یافته است. به عنوان مثال تابع sayName دارای یک آرگومان ورودی است و خروجی نیز عدد 1 را نمایش داده است.
توابع apply() و call()
این دو تابع، جهت فراخوانی توابع، با یک مقدار خاص برای شیء this استفاده میشوند؛ در واقع مقدار شیء this را در بدنهی توابع تنظیم میکنند. همانطور که قبلا اشاره شد، شیء this ، به شیء ای اشاره میکند که تابع متعلق به آن است. با توابع فوق میتوانیم اشارهگر this را با مقدار یا شیء دیگری تنظیم کنیم. آرگومان اول هر دوی این توابع، مقداری است که باید به شیء this اختصاص یابد. آرگومان بعدی تابع apply آرایهای است که آرگومانهای ورودی را برای تابع فراخوانی شده فراهم میکند. آرگومانهای بعدی تابع call ، همان آرگومان هایی هستند که به صورت مجزا به تابع فراخوانی شده ارسال میگردند.
var color = "red"; var obj = { color: "blue" }; function sayColor(a, b) { alert(a + " said " + b + ": " + this.color); } sayColor("Sohrab", "Mitra"); sayColor.apply(this, ["Sohrab", "Mitra"]); sayColor.call(this, "Sohrab", "Mitra"); sayColor.apply(obj, ["Sohrab", "Mitra"]); sayColor.call(obj, "Sohrab", "Mitra");
خروجی :
"Sohrab told Mitra: red"
"Sohrab told Mitra: red"
"Sohrab told Mitra: red"
"Sohrab told Mitra: blue"
"Sohrab told Mitra: blue"
همانطور که میدانید یک تابع به صورت پیش فرض متعلق به شیء window میباشد. در سه فراخوانی اول، تابع sayColor ، شیء this ، به شیء window اشاره میکند. بنابراین مقدار red را برای متغیر یا ویژگی color نمایش میدهد. دو فراخوانی آخر که obj را به عنوان آرگومان اول ارسال مینمایند، یعنی شیء this باید با مقدار obj جایگزین شود. بنابراین مقدار blue را برای ویژگی color ، که متعلق به شی obj میباشد، نمایش میدهند.
تنها تفاوت call() و apply() ، شیوهی ارسال آرگومانها به تابع مقصد میباشد. مزیت استفاده از توابع call() یا apply() این است که میتوان یک شیء را به یک تابع تزریق نمود به گونهای که شیء، هیچ اطلاعی از تابع مورد نظر نداشته باشد. این مزیت مورد استفادهی برخی الگوها و معماریها میباشد که در مباحث مربوطه در مورد آن بحث خواهد شد.
تابع bind()
این تابع نمونهای از یک تابع را ایجاد میکند و شیء this آن تابع را، با آرگومان ارسالی به تابع bind ، مقداردهی مینماید.
var color = "red"; var obj = { color: "blue" }; function sayColor() { alert(this.color); } var bindSayColor = sayColor.bind(obj); bindSayColor();
خروجی :
"blue"
در مثال فوق، نمونهای از تابع sayColor ایجاد شده است که شیء obj به عنوان آرگومان ورودی تابع bind ارسال شده است. یعنی مقدار this در تابع bindSayColor به شیء obj اشاره میکند و مقدار ویژگی color شیء obj به عنوان خروجی نمایش مییابد.