C#委托学习

委托

什么是委托?

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

使用委托:

  1. 定义委托
  2. 创建委托实例

声明委托

定义委托:

//定义委托
delegate void IntMethodInvoker(int x);

使用委托

普通使用

使用构造函数实例化

private delegate string GetAString()	//定义委托类型

static void Main(){
	int x = 40;
    //使用委托类型 创建实例	
	GetAString myfun = new GetAString(x.ToString);	//相当于实例化类型 参数为方法 
	Console.WriteLine(myfun())
}

在创建实例的时候,也可以直接赋值方法

private delegate string GetAString()	//定义委托类型

static void Main(){
	int x = 40;
    //使用委托类型 创建实例	
	GetAString myfun = x.ToString;	//相当于实例化类型 参数为方法 
	Console.WriteLine(myfun.Invoke())	//也可通过Invoke调用
}

委托类型作为参数使用

private delegate void PrintString();

static void PrintStr(PrintString print)
{
	print.Invoke();
}

static void Main(){
	PrintString method;
	method = () => Console.WriteLine("666666");		//这里可以指向一个独立的方法
	PrintStr(method);
	Console.ReadKey();
}

委托的多播

private delegate void PrintString();

static void PrintStr(PrintString print)
{
	print.Invoke();
}

static void Main(){
	PrintString method;
    //创建实例、匿名委托
	method = () => Console.WriteLine("666666");		//这里可以指向一个独立的方法
    method += () => Console.WriteLine("委托的多播");
	PrintStr(method);	
    //  666666
    // 	委托的多播
	Console.ReadKey();
}

系统内置委托

除了我们自己定义的委托之外,系统还给我们提供了内置的委托类型,Action&Func

Action

Action委托引用了一个==没有返回值(void)==的方法,T表示方法参数,可以传递0~16个参数类型

Acrion委托

  • Action

  • Action<int>

  • Action<int ,string,bool>

  • ········
    实例代码:

static void Main(string[] args)
{
	// 创建实例
	Action<int> method = delegate(int i) { Console.WriteLine($"这里是使用delegate的委托,参数值																是:{i}"); };
	Action<int> methon1 = (int a) => { Console.WriteLine($"这里是使用匿名委托,参数值是:{a}"); };
	// 执行
	method(12);
	methon1(52);
}

Func

Func引用了一个带有一个返回值的方法,可以传递0~16个参数类型,最后一个值为返回值

  • Func

  • Func<int>

  • Func<int ,string,bool>

  • ········

    实例代码:

static void Main(string[] args)
{
    //匿名方法
	Func<int,string> method2 = delegate(int i) { return i.ToString() + "转换";};
    Console.WriteLine(method2(12));
}

匿名方法

本质还是一个方法,只是没有名字,任何使用委托变量的地方都可使用匿名方法。

只能赋值给委托,由委托调用,减少代码复杂度

比如在winForm中在当前窗口打开另外一个窗口,给数据添加一条新数据,然后通过委托进行对之前表中的内容进行刷新,如果这个方法仅用这一次,就可以使用匿名委托–回调方法

static void Main(string[] args)
{
    Func<string,string> method3 = delegate(string str) {return "这就是"+str;};
    Console.WriteLine(method3("匿名方法"));
}

Lambda表达式

  • 是匿名方法的一种简写形式,也是定义了一个方法
  • Lambda表达式的参数不需要指定参数类型
  • 只有一个参数的时候不需要括号(类似Js箭头函数)
  • 代码只有一句的时候,不需要花括号
  • Lambda可以访问表达式块外部的变量(类似Js箭头函数)
static void Main(string[] args)
{
    // 匿名方法
    Func<string,string> method3 = delegate(string str) {return "这就是"+str;};
    Console.WriteLine(method3("匿名方法"));
    
    //lambda表达式替代匿名方法	无须再指定参数类型	
    Func<string,string> method4 = (arg) => "这就是"+str;	//这时return也可以省略
    Console.WriteLine(method4("匿名方法"));
    
    // 访问外部变量
    int someVal = 5;
    Func<int,int> f = val => val+someVal;
    Console.WriteLine(f(3)); //8
}


应用

通过泛型对冒泡排序进行扩展,可以给任何对象排序

冒泡排序:

bool swapped = true;
do
{
	swapped = false;
	for (int i = 0; i < arr.Length; i++)
	{
		if (arr[i]>arr[i+1])
		{
			int temp = arr[i];
			arr[i] = arr[i + 1];
			arr[i + 1] = temp;
			swapped = true;
		}
	}
} while (swapped);

扩展:

//首先定义一个类
class Employee
    {
        public Employee(string name, decimal salary)
        {
            this.Name = name;
            this.Salary = salary;
        }
        public string Name { get; private set; }
        public decimal Salary { get; private set; }
	    //比较方法
        public static bool CompareSalary(Employee e1, Employee e2)
        {
            return e1.Salary > e2.Salary;
        }
    }

class Program{
// 冒泡排序
public static void Srot<T>(List<T> sortArr, Func<T, T, bool> comparision)
        {
            bool swapped = true;
            do
            {
                swapped = false;
                for (int i = 0; i < sortArr.Count - 1; i++)
                {
                    if (comparision(sortArr[i], sortArr[i + 1]))
                    {
                        T temp = sortArr[i];
                        sortArr[i] = sortArr[i + 1];
                        sortArr[i + 1] = temp;
                        swapped = true;
                    }
                }
            } while (swapped);
        }

static void Main(string[] args)
        {
            Employee e1 = new Employee("111", 152);
            Employee e2 = new Employee("111", 358);
            Employee e3 = new Employee("111", 12);
            List<Employee> list = new List<Employee> {e1, e2, e3};
    	    // 传递比较方法给Sort
            Srot(list, Employee.CompareSalary);
            list.ForEach(r => { Console.WriteLine(r.Salary); });
            Console.ReadKey();
        }
    }

事件

事件基于委托,为委托提供了一个发布/订阅机制,我们可以说事件是一种具有特殊签名的委托。

什么是事件?

事件(Event)是类或对象对其他类或对象通知发生的事情的一种特殊签名的委托。

事件的声明:

public event 委托类型 事件名;

事件使用event关键字来声明,它的返回值是一个委托类型。

通常事件的命名,以名字+Event作为他的名称

基本使用:

namespace _007_事件
{
   public delegate void MyDelegate();
   class Program
   {
       // 	声明一个事件
       public event MyDelegate mydelgate;
       static void Main(string[] args)
       {
           Program p = new Program();
           p.mydelgate = Test1;
           p.mydelgate();
           Console.ReadKey();
       }

       private static void Test1()
       {
           Console.WriteLine("Test");
       }
   }
}

实例:(观察者模式)

三只动物,猫(Tom),两只老鼠(Jerry,Jack),当猫叫(CatShout)的时候,两只老鼠开始逃跑(MouseRun)。

使用委托完成

实体类:

class Cat
    {
        private string name;
        private string color;
	    // 声明一个委托
        public Action catCome;

        public Cat(string name,string color)
        {
            this.name = name;
            this.color = color;
        }

        public void CatComing()
        {
            Console.WriteLine($"{color}的猫:{name}过来了---");
            if (catCome!=null)
            {
                catCome();
            }
            
        }

    }


class Mouse
    {
        private string name;
        private string color;
        public Mouse(string name,string color,Cat cat)
        {
            this.name = name;
            this.color = color;
            // 把自身的逃跑方法注册进猫里面
            cat.catCome += RunAway;
        }

        public void RunAway()
        {
            Console.WriteLine($"{color}的老鼠:{name}说老猫来了。快跑!!!");
        }
    }

Program:

static void Main(string[] args)
        {
            Cat cat = new Cat("Tom","蓝色");
            Mouse m1 = new Mouse("Jerry","黄色",cat);
            Mouse m2 = new Mouse("Jack", "绿色",cat);
            //猫的状态发生改变, 
            cat.CatComing();
            Console.ReadKey();
        }

但是:

委托是可以从外部直接调用到的

cat.catCome();  	// 这个委托是可以直接从外部调用到的

和委托的区别

  • 事件是一种特殊的委托,或者说是受限制的委托,是委托的一种特殊应用,只能施加+=,-=操作符。二者本质上是一个东西。
  • event ActionHandler Tick; //编译成创建一 个私有的委托示例,和施加在其上的add, remove(+=,-=)方法。
  • event只允许用add,remove方法来操作,这导致了它不允许在类的外部被直接触发,只能在类的内部适合的时机触发。委托可以在外部被触发,但是别这么用。
  • 使用中,委托常用来表达回调;事件表达外发的接口。

所以直接将时间变成委托即可,使用方法不变:

// class Cat
public event Action catCome;	//声明一个事件 发布消息


// class Mouse
cat.catCome += RunAway;		//订阅时间

猜你喜欢

转载自blog.csdn.net/qq_36615115/article/details/108574910