Մասնակից:ԱնահիտՀարությունյան
Սա ԱնահիտՀարությունյան մասնակցի սևագրության էջն է՝ «ավազարկղը», և մասնակցի էջի ենթաէջերից մեկն է։ Այն ծառայում է որպես սևագիր և փորձարկումների վայր։ Սա հանրագիտարանային հոդված չէ։ Ձեր անձնական ավազարկղը ստեղծելու համար սեղմեք այստեղ։ Այլ ավազարկղեր՝ Ընդհանուր ավազարկղ |
Դելեգատ (Delegate)
Դելեգատը դա օբյեկտ է, որը հնարավորություն է տալիս նշել մեկ կամ ինչու չէ նաև մի քանի մեթոդներ, որոնք կկանչվեն ավելի ուշ: Դելեգատի օբյեկտը պահում է հետևյալ ինֆորմացիան՝
• Մեթոդի անունը, որը պետք է կանչվի
• Այդ մեթոդի ընդունող արժեքները, եթե կան
• Մեթոդի վերադարձնող արժեքը
Դելեգատները կարող են դիմել ինչպես կլասի սովորական մեթոդին, այնպես էլ ստատիկ մեթոդին: Դելեգատ սահմանելու համար C# ում օգտագործվում է delegate բառը: Դելեգատը կարող է ունենալ ցանկացած անուն միայն թե, այն իր կառուցվածքով պետք է համապատասխանի այն մեթոդի հետ, որն այն կիրառելու է: Բերենք դելեգատի օրինակ
public delegate int BinaryOp(int x, int y); public class SimpleMath { public static int Add(int x, int y) { return x + y; } public static int Subtract(int x, int y) { return x + y; } } class Program { static void Main(string[] args) { Console.WriteLine("-----------------------------------"); BinaryOp b = new BinaryOp(SimpleMath.Add); Console.WriteLine(" 5 + 5 is {0}",b(5,5)); Console.ReadLine(); } static void DisplayDelegateInfo(Delegate obj) { foreach (Delegate item in obj.GetInvocationList()) { Console.WriteLine("Method name = {0}",item.Method); Console.WriteLine("Method type = {0}", item.Target); // այս դեպքում կլասի անունը որպես տիպ / Method type / չի նշվում քանի որ //մեթոդը ստատիկ է, եթե ստատիկ չլիներ ապա այն կունենար օբյեկտ որը ցույց //կտար տվյալ մեթոդը, հետևաբար որպես տիպ կնշեր օբյեկտի տիպը } } }
Տվյալ օրինակում նախ սահմանում ենք դելեգատ int վերադարձնող արժեքով, և երկու int տիպի ընդունող արժեքով: Ապա SimpleMath կլասում հայտարարում ենք երկու մեթոդ, որոնք ունեն նույն կառուցվածքը ինչ դելեգատը, հակառակ դեպքում դելեգատի միջոցով այն հնարավոր չի լինի կանչել: Ապա main-ում ստեղծելով դելեգատի օբյեկտ կանչում ենք համապատասխան մեթոդը: Արդյունքում մենք կարողացանք կանչել մեթոդը դելեգատի միջոցով , որը հնարավորություն է տալիս SimpleMath.Add մեթոդը փոխելով SimpleMath.Subtract ստանալ հանման գործողությունը: Դելեգատը հնարավորություն է տալիս մեթոդին որպես պարամետր փոխանցել մեթոդ : Որպեսզի իմանանք թե տվյալ դելեգատը ինչ մեթոդեր ունի պետք է կանչել GetInvocationList(), որը վերադարձնում է դելեգատի մեթոդները: Մեթոդի անվանումը կարելի է ստանալ Method, իսկ տիպը Target գործիքների միջոցով:
Դելեգատի ներքին նկարագրություն
Երբ C#-ի կոմպիլիատորը հանդիպում է դելեգատի, այն գեներացնում է հատուկ կառուցվածքով կլաս, որը թույլ է տալիս պահել մեթոդների ցանկը, որոնց պետք է դիմի հետագայում: Օրինակ Public delegate string MyDelegate (bool a, int b); դելեգատի դեպքում կոմպիլիատորը կստեղծի կլաս նույն անունով (MyDelegate)
sealed class MyDelegate:System.MulticastDelegate { public string Invoke(bool a, int b); public IAsyncResult BeginInvoke(bool a, int b, AsyncCallback cb, object state); public string EndInvoke(IAsyncResult result); }
Դելեգատը որպես պարամետր կարող է ունենալ նաև ref out պարամետրեր:
Դիտարկենք հետևյալ դեպքը, երբ ունենք Աշխատակիցներ կլասը, որն ունի PromoteEmployee /կոչում տալ աշխատակցին/ մեթոդը, և քանի որ աշխատակիցներից պետք է ընտրվեն նրանք ովքեր բավարում են տվյալ պաշտոնին հատուկ պահանջներին, ունենք պայման, որի ստուգումը կատարվում է ֆունկցիայի միջոցով, վերջինս մեթոդին փոխանցելու հնարավորություն է տվել դելեգատը: Ցանկացած պահին փոխելով փոխանցվող ֆունկցիան /տվյալ դեպքում պայմանը/ կստանանք արդյունք տարբեր պաշտոնների համար: Կոդը ավելի հակիրճ գրելու նպատակով կիրառվել է նաև լյամբդա => հասկացությունը, ինչը հնարավորություն է տալիս փոխանցել ոչ թե մեթոդը, այլ անմիջապես մեթոդի մարմինը` դելեգատին հատուկ կառուցվածքով:
delegate bool checking(Employee emp); class Employee { public int ID { get; set; } public string Name { get; set; } public int Experience { get; set; } public static void PromoteEmployee(List<Employee> ListEmp, checking IsEligibleToPromote) { foreach (Employee item in ListEmp) { if (IsEligibleToPromote(item)) Console.WriteLine("Promote- > {0} with {1} years experiences", item.Name, item.Experience); } } } class Program { static void Main(string[] args) { List<Employee> Emps=new List<Employee>() ; Emps.Add(new Employee (){ID=1,Name="Ann",Experience=5}); Emps.Add(new Employee (){ID=2,Name="Suzi",Experience=1}); Emps.Add(new Employee (){ID=3,Name="Sevak",Experience=2}); Emps.Add(new Employee (){ID=4,Name="Lusine",Experience=3}); Emps.Add(new Employee (){ID=5,Name="Artur",Experience=6}); // 1. Employee.PromoteEmployee(Emps, IsEligibleToPromote); Console.WriteLine("\n Calling the same methos with using lyambda ... \n"); // 2. կամ մեթոդը կարելի է կանչել օգտագործելով լյամբդաի հասկացողությունը, ինչը // թույլ է տալիս փոխանցել ոչ թե ֆունկցիան, այլ նրա մարմինը, այսպես` Employee.PromoteEmployee(Emps, emp => emp.Experience >= 5); Console.ReadLine(); } private static bool IsEligibleToPromote(Employee emp) { if (emp.Experience >= 5) return true; return false; } }
Բազմահասցե դելեգատ (multicast delegate)
Բազմահասցե կոչվում են այն դելեգատները, որոնք ունեն մեկից ավելի ֆունկցիաներին հղումներ: Երբ կանչվում է դելեգատը բոլոր ֆունկցիաները, որին այն ունի հղումներ կանչվում են: Գոյություն ունի բազմահասցե դելեգատ ստեղծելու երկու տարբերակ
• + կամ += գրանցել մեթոդը դելեգատում
• - կամ -= հեռացնել մեթոդը դելեգատից
delegate void SampleDelegate();
// 1. SampleDelegate del1 = new SampleDelegate(SampleMethodOne); SampleDelegate del2 = new SampleDelegate(SampleMethodTwo); SampleDelegate del3 = new SampleDelegate(SampleMethodThree); SampleDelegate del = del1 + del2 + del3 - del2; //2. SampleDelegate del = new SampleDelegate(SampleMethodOne); del += SampleMethodTwo; del += SampleMethodThree;
Եթե դելեգատը ունի վերադարձնող արժեք, և դա բազմահասցե դելեգատ է, ապա միայն վերջին մեթոդի արժեքը կվերադարձնի: Նույնը կարելի է ասել նաև ref և out տեսակի պարամետր փոխանցելու դեպքում: Օրինակ
static void Main(string[] args) { SampleDelegate del = new SampleDelegate(SampleMethodOne); del += SampleMethodTwo; del += SampleMethodThree; int b=200; del(out b); Console.WriteLine(b);} static void SampleMethodTwo(out int a) { a= 2; } static void SampleMethodThree(out int a) { a= 105; }
Այս դեպքում արդյունքը կլինի 105 քանի որ վերջին ֆունկցիան, որը գումարել ենք ունի 105 արժեքը: Սա այն դեպքն է, երբ գումարելիների տեղը փոխելիս գումարը փոխվում է, թեև իրականում այսպիսի դեպքերի համար գումարում չի կատարվում: += և -= գործողությունները համապատասխանում են Delegate.Combine և Delegate.Remove մեթոդներին: Այսպիսի դելեգատները հաճախ օգտագործվում են Design Patternներում:
Ընդհանրացված դելագատներ
Ընդհանրացված դելեգատը կազմվում է <T> ի միջոցով, ինչը հնարավորություն է տալիս ոչ թե նախապես որոշել դելեգատի ընդունող պարամետրի տիպը, այլ կիրառելիս` կանչելիս: Դիտարկենք մեկ ընդհանրացված դելեգատի օրինակ public delegate void MyGenericDelegate<T>(T arg) Սա նշանակում է, որ այս դելեգատի միջոցով կանչվող մոթոդը պետք է ունենա void վերադարձնող արժեք և T տիպի ընդունող պարամետրեր, ընդ որում վերջինս կարող է լինել ցանկացած տիպ, ինչպես օրինակ 1. MyGenericDelegate strdel = new MyGenericDelegate<string>(MyMethodwithstring) Static void MyMethodwithstring(string s) { Console.WriteLine(s); } 2. MyGenericDelegate intdel = new MyGenericDelegate<int>(MyMethodwithint) Static void MyMethodwithint(int i) { Console.WriteLine(i.ToString()); }
Action<> և Func<> ընդհանրացված դելեգատներ
Գոյություն ունեն Action<> և Func<> ընդհանրացված դելեգատները, որոնք սահմանված են System անունների տարածքում: Action<> դելեգատը կարող է կիրառել այն մեթոդները, որոնք ունեն void վերադարձնող արժեք, և կարող են ընդունել մինչև 16 պարամետր, ընդ որում պարամետրերի տիպերը կարող են լինել տարբեր:Օրինակ
static void DisplayMessage(string msg, ConsoleColor txtColor, int printCount) { Console.ForegroundColor = txtColor; for (int i = 0; i < printCount; i++) { Console.WriteLine(msg); } }
Այս մեթոդը կանչող դելեգատը սահմանվում է այսպես`
Action<string, ConsoleColor, int> actDel = new Action<string,ConsoleColor,int>(DisplayMessage); actDel("Hello world", ConsoleColor.Green, 3);
Հիշենք որ Action<> դելեգատի դեպքում մեթոդը անպայման մետք է ունենա void վերադարձնող արժեք, հակառակ դեպքում կարելի է կիրառել Func<> ընդհանրացված դելեգատը, որը ևս կարող է ընդունել ընդուպ մինչև 16 պարամետր, և ի տարբերություն նախորդի ունի հատուկ սահմանված վերադարձնող արժեք:
Դիտարկենք հետևյալ օրինակը static string SumToString(int x, int y) { return (x + y).ToString(); }
Այս մեթոդը կանչող դելեգատը կունենա հետևյալ տեսքը`
Func<int, int, string> funcDel = new Func<int, int, string>(SumToString); Console.WriteLine(funcDel(10,20));
Ինչպես արդեն նկատեցիք, Func<int, int, string> ինչպես և առհասարակ բոլոր Func դելեգատներում <> ում գրված ամենավերջին տիպը վերաբերում է վերադարձվող արժեքին, մնացած տիպերը ընդունվում են որպես ընդունող պարամետրերի տիպեր: