目录

1、什么是委托

2、委托的一般使用

3、多播(multicast)委托


1、什么是委托

  1. 委托(delegate)是函数指针的升级版

实例C/C++中的函数指针

一切皆地址

  1. 变量(数据)是以某个地址为起点的一段内存中所存储的值。
  2. 函数(算法)是以某个地址为起点的一段内存中所存储的一组机器语言指令。

直接调用和间接调用

  1. 直接调用:通过函数名来调用函数,CPU通过函数名直接获得函数所在地址并开始执行->返回
  2. 间接调用:通过函数指针来调用函数,CPU通过读取函数指针存储的值获得函数所在地址并开始执行->返回

委托的简单使用

Action委托、Func委托

委托的声明(自定义委托)

委托是一种类,类是数据类型所以委托也是数据类型

它的声明方法与一般的类不同,主要是为了照顾可读性

注意声明委托的位置

委托与封装的方法必须类型兼容(返回值的数据类型一致,参数列表在个数和数据类型上一致【参数名不需要一样】)

2、委托的一般使用

实例:把方法当作参数传递给另一个方法

正确使用1:模板方法,借用指定的外部方法来产生结果

  1. 相当于填空题
  2. 常位于代码中部
  3. 委托有返回值

正确使用2:回调(callback)方法,调用指定的外部方法

  1. 相当于流水线
  2. 常位于代码尾部
  3. 委托无返回值

注意:难精通+易使用+功能强大东西,一旦被滥用后果非常严重

  1. 缺点1:这是一种方法级别的紧耦合,现实工作要谨慎
  2. 缺点2:使可读性下降,debug难度增加
  3. 缺点3:把委托回调、异步调用和多线程纠缠在一切,会让代码变得难以阅读和维护
  4. 缺点4:委托使用不当有可能造成内存泄漏和程序性能下降。
using System;
using System.IO;
namespace 委托
{/// <summary>/// 自己声明委托double类型/// </summary>public delegate double Calc(double x,double y);   class Program{/// <summary>/// 定义另一个int委托类型/// </summary>public delegate int TestClass1(int x, int y);static void Main(string[] args){Console.WriteLine(DateTime.Now);Console.OutputEncoding = Encoding.UTF8;#region 调用CalcuLator/*       CalcuLator calcuLator = new CalcuLator();Action action = new Action(calcuLator.Report);//直接调用calcuLator.Report();//间接调用action.Invoke();action();//fUNC委托Func<int, int, int> func1 = new Func<int, int, int>(calcuLator.Add);Func<int, int, int> func2 = new Func<int, int, int>(calcuLator.Sub);Func<int, int, int> func3 = new Func<int, int, int>(calcuLator.Mul);Func<int, int, int> func4 = new Func<int, int, int>(calcuLator.Div);int x = 100;int y = 200;int z = 0;z = func1.Invoke(x,y);Console.WriteLine(z);z = func2.Invoke(x, y);Console.WriteLine(z);z = func3.Invoke(x, y);Console.WriteLine(z);z = func4.Invoke(x, y);Console.WriteLine(z);*/#endregion#region 使用委托CalcuLator1 calcuLator1 = new CalcuLator1();Calc calc1 = new Calc(calcuLator1.Add);Calc calc2 = new Calc(calcuLator1.Sub);Calc calc3 = new Calc(calcuLator1.Mul);Calc calc4 = new Calc(calcuLator1.Div);//间接调用double a = 100;double b = 200;double c = 0;c = calc1.Invoke(a, b);Console.WriteLine(c);c = calc2.Invoke(a, b);Console.WriteLine(c);c = calc3.Invoke(a, b);Console.WriteLine(c);c = calc4.Invoke(a, b);Console.WriteLine(c);#endregion#region 使用模板方法/*ProductFactory productFactory = new ProductFactory();//包装工厂的实例WrapFactory wrapFactory = new WrapFactory();Func<Product> func1 = new Func<Product>(productFactory.MakePizza);//方法一生成pizzaFunc<Product> func2 = new Func<Product>(productFactory.MakeToyCar);//方法二生成小汽车//声明logcallback的实例Logger logger = new Logger();Action<Product> log = new Action<Product>(logger.log);//传进模板方法           //开始调用模板方法Box box1= wrapFactory.WrapPdoduct(func1,log); Box box2 = wrapFactory.WrapPdoduct(func2,log);Console.WriteLine(box1.Product.Name);Console.WriteLine(box2.Product.Name);*/#endregion#region 使用回调方法#endregion#region TestClass//初始化实例TestClass ts = new TestClass();//创建委托类型的实例mn,并绑定到Addd()方法TestClass1 mn1 = ts.Addd;//创建委托类型的实例mn,并绑定到Subb()方法TestClass1 mn2 = ts.Subb;//委托的调用int s1 = mn1(5,2);int s2 = mn2(6, 3);Console.WriteLine("运算结果是:"+s1.ToString());Console.WriteLine("运算结果是:" + s2.ToString());#endregion#region 委托打印字符串到控制台和文件//初始化实例PrintString.printString ps1 = new PrintString.printString(PrintString.WriteToFile);PrintString.printString ps2 = new PrintString.printString(PrintString.WriteToFile);//调用PrintString.sendString(ps1);PrintString.sendString(ps2);#endregionConsole.ReadKey();}}#region CalcuLator类/// <summary>/// CalcuLator类/// </summary>class CalcuLator{public void Report(){Console.WriteLine("I Have 3 Methods!");}public int Add(int a , int b){int result = a + b;return result;}public int Sub(int a, int b){int result = a - b;return result;}public int Mul(int a, int b){int result = a * b;return result;}public int Div(int a, int b){int result = a / b;return result;}}#endregion#region CalcuLator1类四个方法加减乘除  class CalcuLator1{public double Add(double x,double y ){return x +y;}public double Sub(double x, double y){return x - y;}public double Mul(double x, double y){return x * y;}public double Div(double x, double y){return x / y;}}#endregion#region 使用回调方法//记录使用程序运行状态//以回调方法传递到模板方法里class Logger{public void log(Product product){Console.WriteLine("Product'{0}' created at '{1}'.Price is {2}",product.Name,DateTime.UtcNow,product.price);}}//模板方法//产品类class Product{//产品名称public string Name { get; set; }//产品价格public double price { get; set; }}//包装箱class Box{public Product Product { get; set; }}//负责包上盒子交给用户class WrapFactory{public Box WrapPdoduct(Func<Product>getProduct,Action<Product>logCallback){//定义模板方法 Box box = new Box();Product product = getProduct.Invoke();  //调用委托//添加是否调用回调方法//如果大于50块钱就log一下if (product.price>=50){logCallback(product);}box.Product = product;return box;}}//生成产品class ProductFactory{//生成披萨public Product MakePizza(){Product product = new Product();product.Name = "Pizza";product.price = 12;return product;}//生成玩具小汽车public Product MakeToyCar(){Product product = new Product();product.Name = "Car";product.price = 100;return product;}}#endregion#region TestClass测试委托class TestClass{public int Addd(int x, int y){int result = x + y;return result;}public int Subb(int x, int y){int result = x - y;return result;}}#endregion#region 委托打印字符串到控制台class PrintString{static FileStream fs;static StreamWriter sw;//委托声明public delegate void printString(string s);/// <summary>/// 该方法将字符串打印到控制台/// </summary>/// <param name="str"></param>public static void WriteToCon(string str){Console.WriteLine("The String is :{0}",str);}/// <summary>/// 该方法将字符串打印到文件/// </summary>/// <param name="s"></param>public static void WriteToFile(string s){fs = new FileStream("d:\\test.txt",FileMode.Append,FileAccess.Write);sw = new StreamWriter(fs);sw.WriteLine(s);sw.Flush();sw.Close();fs.Close();}/// <summary>///该方法把委托作为参数,并使用它调用方法/// </summary>/// <param name="printString"></param>public static void sendString(printString printString){printString("Hello LIANGZAI");}}#endregion
}

3、多播(multicast)委托

隐式异步调用

同步与异步的简介

  1. 同步:你做完我在你的基础上继续坐
  2. 异步:咱们两个同时做,同步进行

同步调用和异步调用的对比

  1. 每一个运行的程序是一个进程(process)
  2. 每个进程可以有一个或多个线程(thread)
  3. 同步调用是在同一线程内
  4. 异步调用的底层机理是多线程
  1. 串行==同步==单线程,并行==异步==多线程

隐式多线程和显示多线程

  1. 直接同步调用:使用方法名
  2. 间接同步调用:使用单播/多播委托的invoke方法
  3. 隐式异步调用:使用委托的begininvoke
  4. 显示异步调用:使用Thread或Task

应该适时的使用接口(interface)取代一些对委托的使用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace 委托2
{ class Program{/// <summary>/// 委托烧水实例/// </summary>public delegate void DoWorkHandler();public delegate void EndInvoke();static void Main(string[] args){Console.OutputEncoding = Encoding.UTF8;#region MyDelegateTest和委托实现函数指针/*//步骤2:创建delegate对象实例MyDelegateTest.MyDelegate md = new MyDelegateTest.MyDelegate(MyDelegateTest.MyDelegateFunc);//调用delegate对象md("app1");Console.WriteLine("***********************");//调用HandlerHandler.EventHandler(1, 10, 20);Handler.EventHandler(2, 20, 20);*/#endregion#region  委托数组/*Operations[] operations ={MathOperation.Multip,MathOperation.Square};for (int i = 0; i < operations.Length; i++){Console.WriteLine("using operations[{0}]:", i);oper.DisplayNumber(operations[i], 2.02);oper.DisplayNumber(operations[i], 4);}*/#endregion#region 烧水实例同步进行/*Console.WriteLine("开始烧水了!");//一直等到水烧开DoWorkHandler handler = (() =>{//模拟一个耗时操作,例如把水烧开花了5秒钟。Thread.Sleep(5000);Console.WriteLine("水烧好了!");});//这时如果调用Invoke方法,由于Invoke是同步的,线程就会被阻塞,//即:在水没有烧开之前我们无法进行其他任何操作。handler.Invoke();//在水烧开前一直会有阻塞Console.WriteLine("打个游戏吧!!");*/#endregion#region 烧水实例异步进行/*Console.WriteLine("开始烧水了!");//一直等到水烧开DoWorkHandler handler1 = (() =>{//模拟一个耗时操作,例如把水烧开花了5秒钟。Thread.Sleep(5000);Console.WriteLine("水烧好了!");});//这里没有阻塞,我们可以做点其他事情IAsyncResult asyncResult = handler1.BeginInvoke(null, null);while (!asyncResult.IsCompleted){Console.WriteLine("水还没烧好,先干点别的事!");Thread.Sleep(1000);}//水烧好了handler1.EndInvoke(asyncResult);*/#endregion#region 烧水回调方法CallBack/*Console.WriteLine("开始烧水了!");//水正在烧DoWorkHandler handler = (() =>{Thread.Sleep(5000);Console.WriteLine("水烧好了!");});//异步回调IAsyncResult asyncResult = handler.BeginInvoke(new AsyncCallback(CallBack), null);while (!asyncResult.IsCompleted){Console.WriteLine("水还没烧好,干点别的事吧!");Thread.Sleep(1000);}*/#endregion#region Student多播委托//给委托传递具体方法Teacher.DoSomething doSomething = new Teacher.DoSomething(Student.MakeTea);doSomething += Student.MakeTea;//委托被赋予了具体方法doSomething();#endregion#region  按照员工的工资进行排序(冒泡排序)//类实例数组Employee[] employee = {new Employee("Bugs Bunny ",2500),new Employee("Elmer Fudd ", 4200),new Employee("Daffy Duck", 3700),new Employee("Wile Coyote ", 7500),new Employee("Any ener ", 6000)};BubbleSorter.Sort(employee, Employee.compareSalary);//对排序好的资金进行遍历foreach (var i in employee){Console.WriteLine(i);}#endregion#region 匿名委托string mid = ",middle pat";Func<string, string> anonDel = delegate (string param){param += mid;param += "and this was added to the string ";return param;};Console.WriteLine(anonDel("Start of String"));#endregionConsole.ReadKey();}#region 烧水回调方法CallBackpublic static void CallBack(IAsyncResult result){DoWorkHandler handler = (result as AsyncResult).AsyncDelegate as DoWorkHandler;handler.EndInvoke(result);}#endregion}#region MyDelegateTestclass MyDelegateTest{//步驟1:声明delegate对象public delegate void MyDelegate(string name);//这是我们想要传递的方法,需要和MyDelegate有相同的参数和返回值类型public static void MyDelegateFunc(string name){Console.WriteLine("Hello,", name);}}#endregion#region 委托实现函数指针class MathClass{public static int max(int a,int b){return (a > b ? a : b);}public static int min(int a, int b){return (a < b ? a : b);}public static int sub(int a, int b){return (a+b);}public static int minus(int a, int b){return (a-b);}}class Handler{private delegate int Calcl(int a,int b);private static Calcl[] myCalcl = new Calcl[2];public static void EventHandler(int i ,int a, int b){switch (i){case 1:myCalcl[0] = new Calcl(MathClass.max);//最大值myCalcl[1] = new Calcl(MathClass.min);//最小值Console.WriteLine(myCalcl[0](a,b));Console.WriteLine(myCalcl[1](a,b));break;case 2:myCalcl[0] = new Calcl(MathClass.sub);//和myCalcl[1] = new Calcl(MathClass.minus);//差Console.WriteLine(myCalcl[0](a,b));Console.WriteLine(myCalcl[1](a,b));break;default:return;}}}#endregion#region  委托数组/// <summary>/// 该数组的元素初始化为MathOperations类的不同操作,遍历这个数组,可以将每个操作应用到2个不同的值中。/// 这种用法的好处是,可以在循环中调用不同的方法。/// </summary>/// <param name="x"></param>/// <returns></returns>delegate double Operations(double x);class oper{public static void DisplayNumber(Operations action,double value){double result = action(value);Console.WriteLine("input value is {0},result of operation {1}", value,result);}}struct MathOperation{public static double Multip(double value){return value * 2;}public static double Square(double value){return value * value;}}#endregion#region Student多播委托class Student{public static void MakeTea(){Console.WriteLine("Got it!");}public static void BuyPen(){Console.WriteLine(" On my way!");}}class Teacher{//声明一个委托public delegate void DoSomething();}#endregion#region 按照员工工资冒泡排序class BubbleSorter{static public void Sort<T>(IList<T> sortArray, Func<T, T, bool> comparison){bool swapped = true;do{swapped = false;for (int i = 0; i < sortArray.Count -1 ; i++){if (comparison(sortArray[i+1],sortArray[i])){T temp = sortArray[i];sortArray[i] = sortArray[i + 1];sortArray[i + 1] = temp;}}} while (swapped);}}class Employee{public Employee(string name,decimal salary){this.Name = name;this.Salary = salary;}public string Name { get; set; }public decimal Salary { get; set; }public override string ToString(){return string.Format("{0},{1:C}", Name, Salary);}public static bool compareSalary(Employee e1,Employee e2){return e1.Salary < e2.Salary;}}#endregion
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace 事件
{class Program{static void Main(string[] args){#region 委托高级应用单播、多播、隐式在、显示//使用委托调用homework方法Student stu1 = new Student() { ID = 1, PenColor = ConsoleColor.Yellow };Student stu2 = new Student() { ID = 2, PenColor = ConsoleColor.Green };Student stu3 = new Student() { ID = 3, PenColor = ConsoleColor.Blue };Student stu4 = new Student() { ID = 4, PenColor = ConsoleColor.DarkMagenta };//使用Action委托Action action1 = new Action(stu1.DoHomework);Action action2 = new Action(stu2.DoHomework);Action action3 = new Action(stu3.DoHomework);Action action4 = new Action(stu4.DoHomework);//单播委托/*action1.Invoke();action2.Invoke();action3.Invoke();action4.Invoke();*///多播委托把2.3.4使用拉姆达表达式合并到1/*action1 += action2;action1 += action3;action1 += action4;          //只调用action1看效果action1.Invoke();*//*//第一种同步调用、直接同步调用,直接调用方法名stu1.DoHomework();stu2.DoHomework();stu3.DoHomework();stu4.DoHomework();//主线程还有事情要做for (int i = 0; i < 10; i++){Console.ForegroundColor = ConsoleColor.Cyan;Console.WriteLine("Main thread {0}",i);Thread.Sleep(1000);}*///第二种使用单播委托进行——间接同步调用/*action1.Invoke();action2.Invoke();action3.Invoke();action4.Invoke();for (int i = 0; i < 10; i++){Console.ForegroundColor = ConsoleColor.Cyan;Console.WriteLine("Main thread {0}", i);Thread.Sleep(1000);}*///第三种多播委托也是间接同步调用/*action1 += action2;action1 += action3;action1 += action4;action1.Invoke();for (int i = 0; i < 10; i++){Console.ForegroundColor = ConsoleColor.Cyan;Console.WriteLine("Main thread {0}", i);Thread.Sleep(1000);}*///使用BeginInvoke委托进行隐式异步调用——回调方法,不需要回调是填null/*action1.BeginInvoke(null,null);action2.BeginInvoke(null, null);action3.BeginInvoke(null, null);action4.BeginInvoke(null, null);for (int i = 0; i < 10; i++){Console.ForegroundColor = ConsoleColor.Cyan;Console.WriteLine("Main thread {0}",i);Thread.Sleep(1000);}*///显示的异步调用//1、古老的方式/*Thread thread1 = new Thread(new ThreadStart(stu1.DoHomework));Thread thread2 = new Thread(new ThreadStart(stu2.DoHomework));Thread thread3= new Thread(new ThreadStart(stu3.DoHomework));Thread thread4 = new Thread(new ThreadStart(stu4.DoHomework));thread1.Start();thread2.Start();thread3.Start();thread4.Start();for (int i = 0; i < 10; i++){Console.ForegroundColor = ConsoleColor.Cyan;Console.WriteLine("Main thread {0}", i);Thread.Sleep(1000);}*///2、使用Task都会发生资源争抢/*Task task1 = new Task(new Action(stu1.DoHomework));Task task2 = new Task(new Action(stu2.DoHomework));Task task3 = new Task(new Action(stu3.DoHomework));Task task4 = new Task(new Action(stu4.DoHomework));task1.Start();task2.Start();task3.Start();task4.Start();*/#endregion#region 简单接口的认识/*IProductFactory pizzaFactory = new PizzaFactory();IProductFactory toycarFactory = new ToyCarFactory();WrapFactory wrapFactory = new WrapFactory();Box box1 = wrapFactory.WrapPdoduct(pizzaFactory);Box box2 = wrapFactory.WrapPdoduct(toycarFactory);Console.WriteLine(box1.Product.Name);Console.WriteLine(box2.Product.Name);*/#endregion#region 简单事件的认识//初始化实例Incrementer incrementer = new Incrementer();Dozens dozens = new Dozens(incrementer);SomeOtherClass someOtherClass = new SomeOtherClass(incrementer);incrementer.DoCount();           #endregion  Console.ReadKey();}}#region 委托高级应用单播、多播、隐式在、显示class Student{/// <summary>/// 学生ID/// </summary>public int ID{get;set;}/// <summary>/// 学生使用笔的颜色/// </summary>public ConsoleColor PenColor{get;set;}/// <summary>/// 实例方法做作业/// </summary>public void DoHomework(){for (int i = 0; i < 5; i++){Console.ForegroundColor = this.PenColor;Console.WriteLine("Student {0} doing homework {1} hours", this.ID, i);//调用线程1000毫秒,也就是1秒钟Thread.Sleep(1000);}}}#endregion#region 简单接口的认识interface IProductFactory{Product Make();}/// <summary>/// 重构购买/// </summary>class PizzaFactory : IProductFactory{public Product Make(){Product product = new Product();product.Name = "Pizza";product.price = 12;return product;}}class ToyCarFactory : IProductFactory{public Product Make(){Product product = new Product();product.Name = "Car";product.price = 100;return product;}}class Product{public string Name { get; set; }public double price { get; set; }}class Box{public Product Product { get; set; }}class WrapFactory{public Box WrapPdoduct(IProductFactory productFactory){//定义模板方法 Box box = new Box();Product product = productFactory.Make();//添加是否调用回调方法return box;}}// 生成产品/*class ProductFactory{//生成披萨public Product MakePizza(){Product product = new Product();product.Name = "Pizza";product.price = 12;return product;}//生成玩具小汽车public Product MakeToyCar(){Product product = new Product();product.Name = "Car";product.price = 100;return product;}}*/#endregion#region 简单事件的认识delegate void Handler();class Incrementer  //发布者{public event Handler CountedADozen;public void DoCount() //触发事件的方法{for (int i = 1; i < 50; i++){//每增加12小时个计时器就触发事件一次if (i%12==0&&CountedADozen !=null){CountedADozen();}}}}class Dozens{public Dozens(Incrementer incrementer){//在发布私有委托里添加方法incrementer.CountedADozen += IncrementDozensCount;}//事件成员被触发时调用的方法void IncrementDozensCount(){Console.WriteLine("Dozens");}}class SomeOtherClass{public SomeOtherClass(Incrementer incrementer){//在发布私有委托里添加方法incrementer.CountedADozen += DoSomething;}//事件成员被触发时调用的方法public void DoSomething(){Console.WriteLine("SomeOtherClass");}}#endregion
}

C#学习记录(七)委托、高级委托相关推荐

  1. 【多线程】学习记录七种主线程等待子线程结束之后在执行的方法

    最近遇到一个问题需要主线程等待所有的子线程结束,才能开始执行,统计所有的子线程执行结果,返回,网上翻阅各种资料,最后记录一下,找到七种方案 第一种:while循环 对于"等待所有的子线程结束 ...

  2. Java学习记录 类的高级特性篇

    Java类包 Java JDK API中提供了类功能,它们封装为类包 类名冲突 JDK API 中提供的类,在同一类包 同类名 会导致编译器无法执行 ,要把类包分开或更改类名 完整的类路径 完整的类名 ...

  3. JavaScript学习记录七

    Typora查看文档工具 Document对象 * JavaScript分三个部分:     * ECMAScript标准:JS的基本的语法     * DOM:Document Object Mod ...

  4. c语言第七章作业,C语言学习第七章

    今天开始学习指针,指针在C语言中具有很重要的地位,按照老师所说,学C学不好指针跟没学一样,可见指针在C语言中的重要地位.废话不多说,首先我们先要知道什么是指针. 指针:指针是一个变量,它存储另一个对象 ...

  5. C++高级编程(第3版)_学习记录

    <C++高级编程(第3版)> Professional C++, Third Edition [美]Narc Gregoire 著,张永强 译,清华大学出版社,2015.5第1版 文章目录 ...

  6. 学习Kotlin(六)扩展与委托

    推荐阅读: 学习Kotlin(一)为什么使用Kotlin 学习Kotlin(二)基本语法 学习Kotlin(三)类和接口 学习Kotlin(四)对象与泛型 学习Kotlin(五)函数与Lambda表达 ...

  7. 《SysML精粹》学习记录--第七章

    <SysML精粹>学习记录 第七章:序列图 序列图简介 序列图元素 消息 约束 组合片段 交互使用 小结 第七章:序列图 序列图简介   序列图是另一种可以用来说明系统动态行为信息的Sys ...

  8. 【Python】 Python编程基础练习100题学习记录第七期(61~70)

    1.此为GitHub项目的学习记录,记录着我的思考,代码基本都有注释. 2.可以作为Python初学者巩固基础的绝佳练习,原题有些不妥的地方我也做了一些修正. 3.建议大家进行Python编程时使用英 ...

  9. C#学习笔记(十三)委托——一切皆地址

    委托(delegate)是函数指针的"升级版".C/C++中的函数指针. C语言中的函数指针: #include<stdio.h>// 声明函数指针,定义为一种数据类型 ...

最新文章

  1. 词袋模型(bag of words)构建并使用主题模型(topic models)特征进行文本聚类分析(clustering analysis)实战
  2. 求Fibonacci数列的前20项
  3. junction.exe 放在哪_情侣拥抱的5种姿势,可以看出感情深浅,你们属于哪一种?...
  4. 用 C 语言开发一门编程语言 — 抽象语法树
  5. Apple watch 开发指南(1) 预览
  6. ImportError: cannot import name ‘python_2_unicode_compatible‘
  7. Dataway让 Spring Boot 开发变得更高效!
  8. AC日记——集合位置 洛谷 P1491
  9. 《Node.js区块链开发》
  10. 用tinypng插件创建gulp task压缩图片
  11. ps魔棒工具抠图和合成图
  12. K8S---多节点部署---基于单节点(5)
  13. 显示器尺寸 和 屏幕分辨率 和 有源信号分辨率 关系
  14. 多多情报通:拼多多卖茶叶需要食品许可证吗?还需要什么证件?
  15. Spring集成JPA提示Not an managed type
  16. 我们选择登月(肯尼迪总统在赖斯大学的演讲)
  17. sql注入bypass方法
  18. python项目中的self到底是什么?
  19. QQ2011 Beta3透明皮肤主界面修改详细教程
  20. 打造建筑行业数字化新标杆: 软通动力联合华为云AI+RPA助力中铁十一局智能化升级

热门文章

  1. Activiti6.0表结构完整分析记录
  2. ifstream java_使用ifstream :: seekg和tellg获取文件大小
  3. u大师u盘装系统win7_u盘怎么安装win7系统 u盘安装win7系统教程【详细介绍】
  4. Cocos2D手机游戏开发之优化篇
  5. 高频面试题之this指向问题
  6. 关于时间格式 2016-08-9T10:01:54.123Z 20160809100154.123Z 处理方法
  7. 激活函数sigmoid、tanh、relu
  8. Word中插入的公式再次打开后字体变大的问题
  9. absolute绝对定位.实现水平垂直居中
  10. virbr0怎么关闭_kvm下关闭virbr0与打开virbr0