Delegate در سی شارپ
private StateMachine<string, string> stateMachine; private StateMachineCOM source; private string startState; public delegate void UnhandledTriggerDelegate(State state, StateConfig trigger); public delegate void EntryExitDelegate(); public delegate bool GuardClauseDelegate(); public string Id; public EntryExitDelegate OnEntry = null; public EntryExitDelegate OnExit = null; public GuardClauseDelegate GuardClauseFromToTrigger = null; public UnhandledTriggerDelegate OnUnhandledTrigger = null; public StateMachineRequest(StateMachineCOM source, string startStateId) { this.source = source; this.startState = startStateId; } public void Configure() { this.stateMachine = new StateMachine<string, string>(startState); var states = source.States; states.ForEach(state => { var triggers = source.StateConfigs.AsQueryable() .Where(config => config.FromStateId == state.StateId) .Select(config => new {Id=config.TransitionId.ToString(), From= config.FromStateId.ToString(), To= config.ToStateId.ToString(), Permit=config.PermiteAction }) .ToList(); triggers.ForEach(trig => { this.stateMachine.Configure(state.StateId.ToString()) }); }); } public bool TryFireTrigger(string TrigerId) { if (!stateMachine.CanFire(TrigerId)) { return false; } stateMachine.Fire(TrigerId); return true; } public string GetCurrentState() { return this.stateMachine.State; }
باشد یعنی Stateها Transitionها و ... را بعد از Fetch کردن از بانک اطلاعاتی به State Machine ارسال کنیم. حالا برای در نظر گرفتن شروط مربوط به OnEntry و OnExit یا GuardClauseFromToTrigger پیشنهاد شما توجه به اینکه براساس State میبایست این متدها ساخته شوند چیست؟
- آیا بهتر است delegate پارامتر دریافت کند؟
اگر بله پیاده سازی آن در هنگام کانفیگ به چه صورت است؟ به این صورت ؟
this.stateMachine.Configure(state.StateId.ToString()) .OnEntry(() => { if (state.OnEnter) OnEntry(trig.Id);}) .OnExit(() => { if (state.OnExit) OnExit(trig.Id); }) .PermitIf(trig.From, trig.To, () => { if (trig.Permit) return GuardClauseFromToTrigger(); return true; });
معماری لایه بندی نرم افزار #4
از آنجا که flexible و reusable بودن برنامهها را نمیتوان نادیده گرفت تا آنجا که این تفکیک پذیری خود به مسئله ای بغرنج تبدیل نشده و تکرر دادهها و پاس دادن غیر ضرور آنها را موجب نشود تلاش در این باره مفید خواهد بود .
امروزه توسعه دهنده گان به سمت کم کردن لایههای فرسایشی و حذف پیچیدگیهای غیر ضرور قدم بر میدارند. خلق عبارات لامبادا در دات نت و delegate ها نمونه هایی از تلاش بشر برنامه نویس در این باره است .
راهبری در Silverlight به کمک الگوی MVVM
- ضمنا MVVM Light toolkit سورس باز است. کلاس Messenger آنرا جدا کنید و استفاده کنید (اگر از کل آن نمیخواهید استفاده کنید).
یک روش هم اینجا دیدم که خیلی جالب است:
http://forums.silverlight.net/forums/p/198684/463126.aspx
از NavigateUri یک HyperlinkButton استفاده کرده. فقط UriMapper را هم تنظیم کرده برای زیبایی کار.
(نیاز به هیچ کتابخانه جانبی هم ندارد. نیازی به دخالت MVVM هم ندارد.و مهمتر از همه، نیازی به کد نویسی هم اصلا ندارد.)
ولی برای پاس دادن یک وهله از صفحه جاری به صفحه بعد (مثل لینک داخل صفحات وب)، کلاس Messenger واقعا تر و تمیز و عالی است. (نیازی هم به استفاده از کوئری استرینگ یا هر روش دیگری نیست)
در برخی از مواقع بر روی اشیاء یک لیست، در یک کلاس، با استفاده از حلقههای foreach یا for کارهای متفاوتی انجام میشود. به عنوان مثال در یک لیست که از سطرهای فاکتور تشکیل شده است، میخواهیم جمع مقادیر کلیه سطرهای فاکتور یا جمع مبلغ یا مالیات یا تخفیف آنها را بدست آوریم . با وجود سادگی حلقههای foreach و for، ممکن است که در برخی از مواقع از راه متفاوتی استفاده شود. برای مثال اجازه بدهید مثال ذیل را با هم بررسی کنیم:
در کلاس Invoice دو متد وجود دارد با نام های CalculateTotalTax و CalculateTotal
متد CalculateTotalTax مجموع مالیات و متد CalculateTotal مجموع مقدار این فاکتور را بدست میآورد .
public float CalculateTotalTax1() { IList<InvoiceLineItem> invoiceLineItem = new List<InvoiceLineItem>(); Decimal result = 0M; foreach (InvoiceLineItem index in invoiceLineItem) { result += (Decimal)index.CalculateTax(); } return (float)result; } public float CalculateTotal() { IList<InvoiceLineItem> invoiceLineItem = new List<InvoiceLineItem>(); Decimal result = 0M; foreach (InvoiceLineItem index in invoiceLineItem) { result += (Decimal)index.CalculateSubTotal(); } return (float)result; }
ما میتوانیم مسئولیت چرخش در لیست سطرهای فاکتور را از این متدها برداریم و آن را از IEnumerable جدا کنیم؛ به وسیله ایجاد یک متد که پارامتر ورودی Action<T> delegate را دریافت میکند و این delegate را برای هر سطر در هر چرخش اجرا میکند.
public void PerformActionOnAllLineItems(Action<InvoiceLineItem> action) { IList<InvoiceLineItem> invoiceLineItem = new List<InvoiceLineItem>(); invoiceLineItem.Add(new InvoiceLineItem { Id = 1, amount = 10, Price = 10000 }); invoiceLineItem.Add(new InvoiceLineItem { Id = 2, amount = 10, Price = 10000 }); invoiceLineItem.Add(new InvoiceLineItem { Id = 3, amount = 10, Price = 10000 }); invoiceLineItem.Add(new InvoiceLineItem { Id = 4, amount = 10, Price = 10000 }); foreach (InvoiceLineItem index in invoiceLineItem) { action(index); } }
و همچنین میتوانیم دو متد خود را به شکل ذیل تغییر دهیم
float CalculateTotal() { Decimal result = 0M; PerformActionOnAllLineItems(delegate(InvoiceLineItem ili) { result += (Decimal)ili.CalculateSubTotal(); }); return (float)result; } float CalculateTotalTax() { Decimal result = 0M; PerformActionOnAllLineItems(delegate(InvoiceLineItem ili) { result += (Decimal)ili.CalculateTax(); }); return (float)result; }
سورس نمونه :Advancedduplicatecoderefactoring.rar
- همه مردان استیو جابز | www.caffecinema.com
- تقویم فارسی جاوا اسکریپت | amib.ir
- چک لیست شکست در RUP | hamidreza.info
- سیر تکاملی Delegate ها - قسمت چهارم، Func and Action | www.persiadevelopers.com
- مجله کامپیوتر - دانلود کتاب آموزش نرم افزار Microsoft Word 2007 | pcmagblog.blogfa.com
- مدرسه هوشمند ایرانی - مقایسه مدارس ژاپن با مدارس ایران | smartschool-ir.blogfa.com
- Dark Pastel Visual Studio Theme | www.servicestack.net
- مدلی دیگر از refactoring یک عبارت if | blog.drorhelper.com
در پروژه های خود از کلمه کلیدی var در #C چگونه استفاده می کنید؟
var result = await query.select( p => new { Id = p.Id , Title = p.Xname } ).ToListAsync();
var companys = new List<Company>();
Thickbox یکی از پلاگینهای jQuery است که جهت نمایش صفحات modal بکار میرود.
روش استفاده بسیار سادهای هم دارد:
الف) jquery.js باید به صفحه معرفی شود.
ب) سپس thickbox.js باید به صفحه الحاق شود.
ج) و فایل css آن یعنی thickbox.css نیز باید به صفحه افزوده شود.
برای استفاده از آن کافی است یک لینک به صفحه اضافه کنید که ویژگی class آن مساوی thickbox باشد. مثلا:
<a href="#TB_inline?height=155&width=300&inlineId=hiddenModalContent&modal=true" class="thickbox">Show hidden modal content.</a>
<a href="iframeModal.html?placeValuesBeforeTB_=savedValues&TB_iframe=true&height=200&width=300&modal=true" title="add a caption to title attribute / or leave blank" class="thickbox">Open iFrame Modal</a>
و مثالهای دیگری از این دست که در صفحه رسمی آن موجود است و نیازی به تکرار آنها نیست.
اما مشکلی که در بلاگر وجود دارد این است که شما نمیتوانید این ویژگیها را در بسیاری از موارد به صورت دستی تنظیم کنید. یک ویجت ظاهر میشود که فقط به شما امکان ثبت یک عنوان و لینک مربوطه را میدهد و همین.
برای انتساب ویژگیهای thickBox به این نوع لینکها که کنترلی روی آن نیست میتوان از خود jQuery کمک گرفت:
$(document).ready(function(){
$("a[href='http://www.mysite.com/page.htm?TB_iframe=true&height=340&width=530']").each(function(){
var obj = $(this);
obj.attr("title","Contact me");
obj.attr("class","thickbox");
}).bind("contextmenu",function(e){
return false;
});
});
همچنین در اینجا کلیک راست نیز بر روی این لینک بسته شده تا کاربر فقط کلیک معمولی را انجام دهد (فقط روی همین یک لینک در صفحه اعمال میشود و نه کل صفحه).
سیر تکاملی delegates را در مثال ساده زیر میتوان ملاحظه کرد:
using System; namespace ActionFuncSamples { public delegate int AddMethodDelegate(int a); public class DelegateSample { public void UseDelegate(AddMethodDelegate addMethod) { Console.WriteLine(addMethod(5)); } } public class Helper { public int CustomAdd(int a) { return ++a; } } class Program { static void Main(string[] args) { Helper helper = new Helper(); // .NET 1 AddMethodDelegate addMethod = new AddMethodDelegate(helper.CustomAdd); new DelegateSample().UseDelegate(addMethod); // .NET 2, anonymous delegates new DelegateSample().UseDelegate(delegate(int a) { return helper.CustomAdd(a); }); // .NET 3.5 new DelegateSample().UseDelegate(a => helper.CustomAdd(a)); } } }
در دات نت یک، یک وهله از شیء AddMethodDelegate ساخته شده و سپس متدی که امضایی متناسب و متناظر با آن را داشت، به عنوان متد انجام دهنده مسئولیت معرفی میشد. در دات نت دو، اندکی نحوه تعریف delegates با ارائه delegates بینام، سادهتر شد و در دات نت سه و نیم با ارائه lambda expressions ، تعریف و استفاده از delegates باز هم سادهتر و زیباتر گردید.
به علاوه در دات نت 3 و نیم، دو Generic delegate به نامهای Action و Func نیز ارائه گردیدهاند که به طور کامل جایگزین تعریف طولانی delegates در کدهای پس از دات نت سه و نیم شدهاند. تفاوتهای این دو نیز بسیار ساده است:
اگر قرار است واگذاری قسمتی از کد را به متدی محول کنید که مقداری را بازگشت میدهد، از Func و اگر این متد خروجی ندارد از Action استفاده نمائید:
Action<int> example1 = x => Console.WriteLine("Write {0}", x); example1(5); Func<int, string> example2 = x => string.Format("{0:n0}", x); Console.WriteLine(example2(5000));
پس از این مقدمه، در ادامه قصد داریم مثالهای دنیای واقعی Action و Func را که در سالهای اخیر بسیار متداول شدهاند، بررسی کنیم.
مثال یک) ساده سازی تعاریف API ارائه شده به استفاده کنندگان از کتابخانههای ما
عنوان شد که کار delegates، واگذاری مسئولیت انجام کاری به کلاسهای دیگر است. این مورد شما را به یاد کاربردهای interfaceها نمیاندازد؟
در interfaceها نیز یک قرارداد کلی تعریف شده و سپس کدهای یک کتابخانه، تنها با امضای متدها و خواص تعریف شده در آن کار میکنند و کتابخانه ما نمیداند که این متدها قرار است چه پیاده سازی خاصی را داشته باشند.
برای نمونه طراحی API زیر را درنظر بگیرید که در آن یک interface جدید تعریف شده که تنها حاوی یک متد است. سپس کلاس Runner از این interface استفاده میکند:
using System; namespace ActionFuncSamples { public interface ISchedule { void Run(); } public class Runner { public void Exceute(ISchedule schedule) { schedule.Run(); } } public class HelloSchedule : ISchedule { public void Run() { Console.WriteLine("Just Run!"); } } class Program { static void Main(string[] args) { new Runner().Exceute(new HelloSchedule()); } } }
نظر شما در مورد این طراحی ساده شده چیست؟
using System; namespace ActionFuncSamples { public class Schedule { public void Exceute(Action run) { run(); } } class Program { static void Main(string[] args) { new Schedule().Exceute(() => Console.WriteLine("Just Run!")); } } }
بدیهی است delegates نمیتوانند به طور کامل جای interfaceها را پر کنند. اگر نیاز است قرارداد تهیه شده بین ما و استفاده کنندگان از کتابخانه، حاوی بیش از یک متد باشد، استفاده از interfaceها بهتر هستند.
از دیدگاه بسیاری از طراحان API، اشیاء delegate معادل interface ایی با یک متد هستند و یک وهله از delegate معادل وهلهای از کلاسی است که یک interface را پیاده سازی کردهاست.
علت استفاده بیش از حد interfaceها در سایر زبانها برای ابتداییترین کارها، کمبود امکانات پایهای آن زبانها مانند نداشتن lambda expressions، anonymous methods و anonymous delegates هستند. به همین دلیل مجبورند همیشه و در همهجا از interfaceها استفاده کنند.
ادامه دارد ...