Функциональный тип в C#. Делегаты
Делегаты Делегат это объект, который обозначает обращение к функции определенного объекта (если функция представляет собой метод экземпляра) или класса (если функция представляет собой статический метод) либо к глобальной функции. Они находят применение для реализации функций обратного вызова или обработки событий, либо во всех случаях, когда необходимо вызывать методы динамически. [ ] delegate ( ); Этим объявлением класса задается функциональный тип - множество функций с заданной сигнатурой, у которых аргументы определяются списком, заданным в объявлении делегата, и тип возвращаемого значения определяется типом результата делегата.
Пример создания делегата namespace Delegates{ delegate void Proc(ref int x); class OwnDel{ public delegate int Fun1(int x); int Plus1( int x){return(x+100);} int Minus1(int x){return(x-100);} void Plus(ref int x){x+= 100;} void Minus(ref int x){x-=100;} public Proc p1; public Fun1 f1; char sign; public OwnDel(char sign) { //конструктор this.sign = sign; if (sign == '+') { p1 = new Proc(Plus); f1 = new Fun1(Plus1); } else { p1 = new Proc(Minus); f1 = new Fun1(Minus1); } } public void TestOwnDel() { int account = 1000, account1=0; OwnDel oda = new OwnDel('+'); oda.p1(ref account); account1=oda.f1(account); Console.WriteLine("account = {0}, account1 = {1}", account, account1); }
class Class1 { delegate void MesToPers(string s); class Person{ public Person() {name =""; id=0; salary=0.0;} public Person(string name) {this.name = name;} //методы public void ToPerson(string mes) { this.message = mes; Console.WriteLine("{0}, {1}",name, message); } //свойства private string name; private int id; private double salary; private string message; } static void Main(string[] args) { Person man1 = new Person("Влад"); // создание объекта делегата MesToPers mestopers = new MesToPers(man1.ToPerson); mestopers("пора работать!"); } Пример создания делегата
Функции высших порядков Функцией высшего порядка называется такой метод класса, у которой один или несколько аргументов принадлежат к функциональному типу. Пример: public class CalcIntegral{//вычисление интеграла public delegate double SubIntegralFun(double x); public double EvalIntegral(double a, double b, double eps, SubIntegralFun sif) { int n=4; double i0=0, i1 = IFun( a, b, n, sif); for( n=8; n < Math.Pow(2.0, 15.0); n*=2) { i0 =i1; i1=IFun(a, b, n, sif); if(Math.Abs(i1-i0)
private double IFun(double a, double b, int n, SubIntegralFun sif) { //Вычисляет частную сумму по методу трапеций double x = a, sum = sif(x)/2, dx = (b-a)/n; for (int i= 2; i
Построение ПС методом раскрутки. Функции обратного вызова Функция высших порядков, написанная во внутреннем слое, задает следующий контракт: "всякая функция, которая собирается меня вызвать, должна передать мне функцию обратного вызова, принадлежащую определенному мной функциональному классу, следовательно, иметь известную мне сигнатуру".
Делегаты как свойства public class Person { public string name = ""; public int age = 0; public double salary = 0; public Person (Person pers) { this.name = pers.name; this.id = pers.id; this.salary = pers.salary; } private static int CompareName(Person obj1, Person obj2) { return (string.Compare(obj1.name, obj2.name)); } private static int CompareSalary(Person obj1, Person obj2) { if (obj1.salary > obj2.salary) return (1); else if (obj1.salary < obj2.salary) return (-1); else return (0); } public static CompareItems SortByName { get { return (new CompareItems(CompareName)); } } public static CompareItems SortBySalary { get { return (new CompareItems(CompareSalary)); } }
public delegate int CompareItems(Person obj1, Person obj2); class Persons{//контейнер объектов Person private int Item = 0; const int n = 100; private Person[] pers = new Person[n]; public void AddPerson(Person ps){ if(Item < n) { Person p = new Person(ps); pers[Item++]= p; } else Console.WriteLine("Не могу добавить Person"); } public void LoadPersons() { } // загрузка должна идти из базы данных public void PrintPersons() { for(int i =0; i
//сортировка public void SimpleSortPerson(CompareItems comp){ Person temp = new Person(); for(int i = 1; i=i; j--) if (comp(pers[j],pers[j-1])==-1) { temp = pers[j-1]; pers[j-1]=pers[j]; pers[j] = temp; } static void Main(string[] args) { Persons persons = new Persons(); persons.LoadPersons(); Console.WriteLine ("Сортировка по имени: "); persons.SimpleSortPerson(Person.SortByName); persons.PrintPersons(); Console.WriteLine ("Сортировка по зарплате: "); persons.SimpleSortPerson(Person.SortBySalary); persons.PrintPersons(); }
Класс Delegate. «Комбинирование делегатов» public abstract class Delegate: ICloneable, ISerializable Создание списка вызывов (invocation list) : del1 = ( ) Combine(del1, del2); del1 = ( ) Remove(del1, del2); или del1 +=del2; del1 - =del2;
Пример: «Жизнь города» delegate void MesToPers(string s); class Servis{ private static void policeman(string mes) { if(mes =="Пожар!") Console.WriteLine(mes + " Милиция ищет виновных!"); else Console.WriteLine(mes +" Милиция здесь!"); } private static void ambulanceman(string mes) { if(mes =="Пожар!") Console.WriteLine(mes + " Скорая спасает пострадавших!"); else Console.WriteLine(mes + " Скорая помощь здесь!"); } private static void fireman(string mes) { if(mes =="Пожар!") Console.WriteLine(mes + " Пожарные тушат пожар!"); else Console.WriteLine( mes + " Пожарные здесь!"); }
public static MesToPers Policeman{ get {return (new MesToPers(policeman));} } public static MesToPers Fireman{ get {return (new MesToPers(fireman));} } public static MesToPers Ambulanceman{ get {return (new MesToPers(ambulanceman));} } static void Main(string[] args) { MesToPers Comb; Comb = (MesToPers)Delegate.Combine(Servis.Ambulanceman, Servis.Policeman); Comb = (MesToPers)Delegate.Combine(Comb, Servis.Fireman); Comb("Пожар!"); Comb = (MesToPers)Delegate.Remove(Comb, Servis.Policeman); //Такое возможно: попытка отключить не существующий элемент Comb = (MesToPers)Delegate.Remove(Comb, Servis.Policeman); Comb("Через 30 минут!"); Comb = (MesToPers)Delegate.Remove(Comb, Servis.Ambulanceman); Comb("Через час!"); Comb = (MesToPers)Delegate.Remove(Comb, Servis.Fireman); Comb = Servis.Ambulanceman; Console.WriteLine( Comb.Method.Name); Comb+= Servis.Fireman; Comb+= Servis.Policeman; Comb("День города!"); Comb -= Servis.Ambulanceman; Comb -= Servis.Fireman; Comb("На следующий день!"); } }
Пример "Плохая служба" public static void BadService(string mes){ int i =7, j=5, k=0; Console.WriteLine("Bad Service: Zero Divide"); j=i/k; } public void TestBadJob(){ MesToPers Comb; Comb = (MesToPers)Delegate.Combine (Servis.Ambulanceman, Servis.Policeman); Comb = (MesToPers)Delegate.Combine(Comb, new MesToPers (Servis.BadService)); Comb = (MesToPers)Delegate.Combine(Comb, Servis.Fireman); foreach(MesToPers currentJob in Comb.GetInvocationList()) { try { currentJob("Пожар!"); } catch(Exception e) { Console.WriteLine(e.Message); Console.WriteLine(currentJob.Method.Name); // BadService }