c#笔记之委托

学委托先知道的知识点

1.一切皆地址

  1. 在电脑中变量是值在内存中储存的地址;
  2. 函数地址里存的是具体的要做的事的机器指令

2.直接调用和间接调用

  1. 直接调用就是通过函数名来调用函数,就是直接通过函数名获取机器指令所在的地址然后开始执行;比如直接调用方法Test();
  2. 间接调用就是通过函数指针来调用函数;就是通过函数指针获取函数名所在的地址,再去读取函数名的值就是机器指令的地址,通过函数名获取机器指令所在的地址然后开始执行;

关于委托的答疑

1.要在一个方法使用另外一个方法为什么要用委托而不是最直接在方法里调用方法

答:因为如果直接调用的话就是写死了只能调用这一种方法,如果用委托把方法当成参数的话就可以很方便的调用不同的方法;所以需要在一个方法里动态使用不同的方法的时候可以用委托;


一、委托的声明

委托就是函数指针的升级版;委托的声明有三种;可以直接用系统自带的action和func以及可以自己创建委托;注意委托里放指向方法的时候不能用()可以看1.1Action里有解释;

1.1Action

Action用于指向没有返回值类型的方法,形参可以有也可以没有;

下面是没参数的情况;注意委托是函数指针的升级版所以需要的是地址,在例子Run方法的第二行创建实例的时候用的是cla.Report2而不是cla.Report2()因为加了()之后就是直接调用方法了这个在所有委托里都一样

cs 复制代码
public void Run()
{
  Cla cla = new Cla();
 Action action = new Action(cla.Report2);声明一个Action变量并且实例化,等号前面是声明后面是实例化还可以直接Action action = cla.Report2;
 
 action();调用还可以用 action.Invoke();
}

class Cal
{

public void Report2()//没参数
{
 console.writeLine("ok");
}
}

有参数的时候声明要加<>这是因为action使用了泛型(泛型就是允许多种类型比如List<>可以多种数据类型,int,string之类)

cs 复制代码
public void Run()
{
  Cla cla = new Cla();
 Action<int> action = new Action<int>(cla.Report);声明一个Action变量并且实例化,等号前面是声明后面是实例化
 action(27);调用还可以用 action.Invoke(27);
}

class Cal
{

public void Report(int x)//参数
{
 console.writeLine(x.tostring());
}
}

1.2Func

适用于有返回类型的时候,参数也是可有可无注意有参数的时候返回值类型要在最后一个;

没参数的情况,也要用泛型的<>;

cs 复制代码
public void Run()
{
  Cla cla = new Cla();
 Func<int> func = new Func<int>(cla.Sub2);
               int xxx= func();
}

class Cal
{

 public int Sub2()
        {
            return 5;
        }
}

有参数的

在有参数的情况下声明的时候前面是参数的类型最后一个是返回值的类型;

cs 复制代码
public void Run()
{
  Cla cla = new Cla();
  Func<string,int> func2 = new Func<string,int>(cla.Sub);
  int xxx1 = func2("jjjj");
}

class Cal
{

 public int Sub(string x)
        {
            Console.WriteLine(x);
            return  2;
        }
}

1.3自定义委托

自定义委托的时候要知道委托也是一种类,要注意声明的地方要在命名空间里面;

定义的形式:公有还是私有 delegate 返回值类型 变量名 (形参);

cs 复制代码
namespace ConsoleApp10
{
    public delegate int WT(string xx);直接命名在命名空间里

 class Program
    {
        static void Main(string[] args)
        {

                Cla cla = new Cla();
              
                WT test = new WT(cla.Sub);
                test("test");//也可以   test.Invoke("d");

        }
    }
     public class Cla
    {
       
        public int Sub(string x)
        {
            Console.WriteLine(x);
            return  2;
        }
       
    }

}

1.4快捷方式

这两种的实例都可以

cs 复制代码
  Action act1 = stu1.DoHomeWork;
 Action act2 = new Action(stu2.DoHomeWork);

二、委托的模板方法和回调方法

委托的调用一般是把一个方法当作参数传给另外一个方法;有两种主要的应用场景:模板方法和回调方法;两者最大的区别就是模板方法是默认一定会执行的;回调方法则是不一定,完全由调用者控制,可能不执行(如传入 null 或条件不满足);

2.1模板方法

就是一个方法里要动态调用多个方法的时候就需要模板方法来把一个委托当作参数这样就可以在方法里使用不同的方法;

exp:比如有一个方法是包装产品,还要两个方法一个生产披萨一个生产汽车;包装产品这个方法就可以使用模板方法,这样这样一个包装方法来动态调用生产披萨和汽车的方法(也可以正常使用两个包装产品的方法来挨个包装披萨和汽车)

cs 复制代码
   class Program
    {
        static void Main(string[] args)
        {
            try
            {
                SC sc = new SC();
                Func<Product> func1 = new Func<Product>(sc.Pizza);
                Func<Product> func2 = new Func<Product>(sc.Car);
                TestFunc(func1);
                TestFunc(func2);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
       static void TestFunc(Func<Product> func)包装的方法
        {
            Product product = new Product();
            product= func();
            Console.WriteLine("包装了"+product.Name);
        }
    }
    public class Product
    {
        public string Name { set; get; }
    }
    public class SC 生产的方法
    {
      public Product Pizza()生产披萨
        {
            Product product = new Product();
            product.Name = "披萨";
            return product;
        }
        public Product Car()生产汽车
        {
            Product product = new Product();
            product.Name = "汽车";
            return product;
        }
    }

2.2回调方法

之所以使用回调方法也是因为为了可以动态调用多个方法,和模板方法的区别就是回调方法的执行是经过判断的不一定执行(try catch或者if else)

exp:还是上面的例子但是加了一个log日志保存给产品加一个价格但生产的价格·高于50就添加log日志;

cs 复制代码
 class Program
    {
        static void Main(string[] args)
        {
            try
            {
                SC sc = new SC();
                LOG log = new LOG();
                Func<Product> func1 = new Func<Product>(sc.Pizza);
                Func<Product> func2 = new Func<Product>(sc.Car);
                Action<Product> action = new Action<Product>(log.Log);
                TestFunc(func1, action);
                TestFunc(func2, action);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
       static void TestFunc(Func<Product> func,Action<Product> action)
        {
            Product product = new Product();
            product= func();
            if(product.Price>50)
            {
                action(product);
            }
            Console.WriteLine("包装了"+product.Name);
        }
    }
    public class LOG
    {
        public void Log(Product product)
        {
            Console.WriteLine("记录" + product.Name);
        }
    }
    public class Product
    {
        public string Name { set; get; }
        public int Price { set; get; }
    }
    public class SC
    {
      public Product Pizza()
        {
            Product product = new Product();
            product.Name = "披萨";
            product.Price = 10;
            return product;
        }
        public Product Car()
        {
            Product product = new Product();
            product.Name = "汽车";
            product.Price = 100;
            return product;
        }
    }

三、委托的多播

多播就是允许一个委托实例包含多个方法调用,用+=、-=来控制方法的数量谁先添加谁先执行;

cs 复制代码
 class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Student stu1 = new Student() { Name = "小明", color = ConsoleColor.Blue };
                Student stu2 = new Student() { Name = "小红", color = ConsoleColor.Yellow };
                Student stu3 = new Student() { Name = "小君", color = ConsoleColor.Red };

                Action act1 = stu1.DoHomeWork;
                Action act2 = new Action(stu2.DoHomeWork);
                Action act3 = new Action(stu3.DoHomeWork);

                act1 += stu3.DoHomeWork;
                act1 += stu1.DoHomeWork;
                act1 += stu2.DoHomeWork;
                //还可以多播委托的实例
                 // act1 += act2;
               // act1 += act3;

                act1();
              
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
      
    }
    public class Student
    {
        public string Name { get; set; }
        public ConsoleColor color { get; set; }
        public void DoHomeWork()
        {
            Console.ForegroundColor = color;
            for (int i=0;i<5;i++)
            {
                Console.WriteLine(Name + "DO" + i.ToString());
                Thread.Sleep(1000);
            }
          
        }
    }

四、同步和异步

1.进程和线程

一个程序打开就是一个进程;一个进程在一开始的时候执行的第一个线程就是主线程;一个进程可以有多个线程;(线程执行是主线程先执行然后再启动其他线程)

2.同步和异步

同步就是一个接一个的执行就是下图中的1;异步就则是多个方法一起调用同时做如下图2,3;

同步调用是在同一个线程里;异步调用就需要多个线程才能实现;

学习时间:

25.0723