委托

62 阅读4分钟

什么是委托

如果我们要把方法当做参数来传递的话,就要用到委托。简单来说委托是一个类型,这个类型可以赋值一个方法的引用。

  1. 定义委托,返回值类型,方法的参数类型,用关键字delegate
  2. 把同返回值和参数类型的方法赋值给delegate声明的变量,方法引用
internal class Program
{
    delegate void IntMethodInvoker(int i);
    delegate void TwoLong(long a, long b);
    delegate string GetAString();
    static void Main(string[] args)
    {
        IntMethodInvoker intvoker = null;
        TwoLong twoLong = null;
        intvoker = test;    //类内静态方法直接使用
        intvoker(10);
        if(twoLong != null)
        {
            twoLong(2, 23);
        }
        int x = 123;
        GetAString getAString = x.ToString;
        GetAString getAString1 = new GetAString(x.ToString);
        Console.WriteLine(getAString);
        
        
    }

    private static void test(int i)
    {
        Console.WriteLine("我是哈哈哈"+i);
    }
}

委托类型数组

MathOp类

internal class MathOp
{
    public static double MultiplayByTwo(double value)
    {
        return value * 2;
    }
    public static double Square(double value)
    {
        return value * value;
    }
}

测试

internal class Program
{
    
    delegate double DoubleOpDelegate(double x);
    static void Main(string[] args)
    {
        
        DoubleOpDelegate[] operations = { MathOp.MultiplayByTwo, MathOp.Square };
        foreach (DoubleOpDelegate operation in operations)
        {
            Console.WriteLine(operation(3));

        }
    
    }

}

委托类型作为参数传递

delegate double DoubleOpDelegate(double x);
static void ProcessAndDisplayRes(DoubleOpDelegate op, double value)
{
    double result = op(value);
    Console.WriteLine(result);

}

Action委托

Action action = Test1;

返回值为void,参数为0个或多个任意类型参数,内置用泛型去设置Action参数

internal class Program
{
    private static void  Test1()
    {
        Console.WriteLine("test1");
    }
    private static void Test2(int x)
    {
        Console.WriteLine("test2"+x);
    }
    private static void Test3(double x, int y)
    {
        Console.WriteLine("test3" + x + y);
    }
    static void Main(string[] args)
    {
        Action action = Test1;
        action();

        Action<int> method = Test2;
        method(124);

        Action<double,int> method2 = Test3;
        Test3(1, 2);
    }
}

Func委托

Func<int,double,string> f2 = Test2;

泛型先设置参数类型,返回值类型在泛型最后设置

internal class Program
{
    private static string Test1()
    {
        return "ssss";
    }
    private static string Test2(int x, double y)
    {
        return "sss" + x + y;
    }
    static void Main(string[] args)
    {
        Func<string> f = Test1;
        Console.WriteLine(f);

        Func<int,double,string> f2 = Test2;
        Console.WriteLine(f2(1,2));
    }
}

用委托升级冒泡排序

普通冒泡排序

internal class Program
{
    private static void Sort(int[] sortArray)
    {
        bool swapped = true;
        do
        {
            swapped = false;
            for (int i = 0;i < sortArray.Length-1; i++)
            {
                if (sortArray[i] > sortArray[i + 1])
                {
                    int temp = sortArray[i];
                    sortArray[i] = sortArray[i + 1];
                    sortArray[i + 1] = temp;
                    swapped = true;
                }
            }
        } while (swapped);
    }
    static void Main(string[] args)
    {
        int[] s = { 1, 2, 6, 4, 52, 5, 6, 7, 23 };
        Sort(s);
        foreach (int i in s)
        {
            Console.WriteLine(i);
        }
    }
}

但是当我们需要排序一个Employee雇员类的数组时,比如想按照雇员工资排序,雇员年龄排序等等,我们应该怎么排序,或者现在想要排序Student类的数组呢,逻辑一样但是要重构排序方法,怎么解决

按照工资排序

雇员类

{
    public string Name {  get; private set; }
    public double Salary {  get; private set; }

    public Employee(string name, double salary)
    {
        Name = name;
        Salary = salary;
    }
    public static bool CompareSalary(Employee a, Employee b)
    {
        return a.Salary > b.Salary;
    }
}

在类里声明了比较两个雇员工资的方法

冒泡排序

public static void Sort<T>(T[] array, Func<T, T, bool> compare)
{
    bool swapped = true;
    do
    {
        swapped = false;
        for (int i = 0; i < array.Length - 1; i++)
        {
            if (compare(array[i], array[i+1]))
            {
                T temp = array[i];
                array[i] = array[i + 1];
                array[i + 1] = temp;
                swapped = true;
            }
        }
    } while (swapped);
}

通过泛型解决了排序对象的类型问题,可以排序各种类型的数组,比如Student类等等,再通过Func委托传递比较大小方法,解决了按照什么数据成员排序的问题,比如可以按照年龄排序,身高排序,工资排序,只需要传入对应的比较两个数大小方法

测试

static void Main(string[] args)
{
    Employee[] employees =
    {
        new Employee("Bunny",20000),
        new Employee("Mich",10000),
        new Employee("si",2000),
        new Employee("cc",1000),
        new Employee("Bunn",30000),
        new Employee("Bunny",20000),

    };

    Sort<Employee>(employees, Employee.CompareSalary);
    foreach (Employee employee in employees)
    {
            Console.WriteLine(employee.Name+":"+employee.Salary);
    }
    
}

多播委托

前面使用的委托都只包含一个方法的调用,但是委托也可以包含多个方法,这种委托叫做多 播委托。

使用多播委托就可以按照顺序调用多个方法,多播委托只能得到调用的最后一个方法的结果,一般我们把多播委托的返回类型声明为void

Action action1 = Test1;
action1 += Test2;
action1 -= Test1;
internal class Program
{
    public static void Test1()
    {
        Console.WriteLine("Test1");
    }
    public static void Test2() 
    { 
        Console.WriteLine("Test2"); 
    }
    static void Main(string[] args)
    {
        Action action1 = Test1;
        action1 += Test2; //action1 = action1 + Test2;
        action1();

        action1 -= Test1;
        action1();
        action1 += Test2;

        //Delegate类,大写是定义通用的委托
        Delegate[] delegates = action1.GetInvocationList();//得到action1委托数组
        foreach (Delegate d in delegates)
        {
            d.DynamicInvoke();//动态调用委托方法
        }

    }
}