c#基础知识---委托,匿名函数,lambda

前言:

C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针。委托是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。委托(Delegate)特别用于实现事件和回调方法。所有的委托都派生自 System.Delegate 类。把一个方法当作参数传递,让其它方法进行调用执行。

1.委托的声明

委托声明决定了可由该委托引用的方法。委托可指向一个与其具有相同标签的方法。

1.1.delegate

1.1.1. 0-23个参数,可以有返回值也可以没有返回值

public delegate int MyDelegateEventHandler (string parm);

注:(1).此委托指向的方法必须是参数为string类型,返回类型为int类型的。其他声明类比所得。

  (2).EventHandler是c# 命名规范,当然我理解规范就是可以随意啦。

(3).委托调用时必须判断是否为null不然会报异常

(4).事件也是一种委托

1.1.2.委托的调用

MyDelegateEventHandler fun=new MyDelegateEventHandler(method);
or
MyDelegateEventHandler fun=method;
// fun不为空,则调用回调方法
 if (fun!= null)
 {
 fun(val);
 }
 //fun?.Invoke(val); 简化版本调用

1.1.3.委托的多播

每个委托都只包含一个方法调用,如果调用多个方法,就需要多次显示调用这个委托。如果同一个委托调用多个方法,我们就可以用多播委托

public delegate void MyDelegate ();

public voidMyMethod()
{
 //#
}
public void MyMethod1()
{
 //#
}
public void MyMethod2()
{
 //#
}
MyDelegateEnventHander myDelegate;
myDelegate=new MyDelegateEventHander(MyMethod);
myDelegate+=new MyDelegateEventHander(MyMethod1);
...........
//调用
myDelegate();

注:

  1.委托对象可使用 "+" 运算符进行合并;

  2."-" 运算符可用于从合并的委托中移除组件委托;

  3.委托指定方法类型必须一致;

  4.返回类型一般为void,但非必须;

  5.GetInvocationList获取委托索引

if (MyDelegate != null)
 System.Delegate[] dels = MyDelegate .GetInvocationList();
for (int i = 0; i < dels.Length; i++)
  {
 MyDelegate -= dels[i] as MethodDelegate;
   }

以上是利用GetInvocationList获取委托索引的一个简单应用。

1.2.Action

Action至少0个参数,至多16个参数,无返回值。

Action 表示无参,无返回值的委托
Action<int,string> 表示有传入参数int,string无返回值的委托
Action<int,string,bool> 表示有传入参数int,string,bool无返回值的委托
Action<int,int,int,int> 表示有传入4个int型参数,无返回值的委托
 public void Test<T>(Action<T> action,T p)
 {
 action(p);
 }

1.3.Func

Func至少0个参数,至多16个参数,根据返回值泛型返回。必须有返回值,不可void

Func是无返回值的泛型委托
Func<int> 表示无参,返回值为int的委托
Func<object,string,int> 表示传入参数为object, string 返回值为int的委托
Func<object,string,int> 表示传入参数为object, string 返回值为int的委托
Func<T1,T2,,T3,int> 表示传入参数为T1,T2,,T3(泛型)返回值为int的委托

1.4.predicate

1.predicate 是返回bool型的泛型委托;

2.predicate<int> 表示传入参数为int 返回bool的委托;

3.Predicate有且只有一个参数,返回值固定为bool;

public delegate bool Predicate<T> (T obj)

2.委托的实例化

2.1.delegate

public delegate int MyDelegateEventHandler (string parm)
public int MyMethod(string parm)
{
 //#
}
MyDelegateEventHandler MyDelegate=new MyDelegateEventHandler(MyMethod)

注:委托实例化的时候,委托对象必须使用 new 关键字来创建,且与一个特定的方法有关。委托参数中的方法不含参数。

2.2.Action的使用

public void Test<T>(Action<T> action, T p)
 {
 action(p);
 }
 private void Action(string s)
 {
 #
 }
//调用
Test<string>(Action,"wyl");

2.3.Func的使用

public int Test<T1, T2>(Func<T1, T2, int> func, T1 a, T2 b)
{
 return func(a, b);
}
private int Fun(int a, int b)
{
 #
}
//调用
Test<int,int>(Fun,100,200)

2.4 委托实现冒泡排序

//定义对象
class Student
 {
 public string Name { get; private set; }
 public decimal Scores{ get; private set; }

 public Student(string name, decimal scores)
 {
 this.Name = name; this.Scores= scores;
 }
 public override string ToString()
 {
 return string.Format("{0},{1:C}",Name,Scores);
 }
 public static bool CompareScores(Student e1,Student e2)
 {
 return e1.Scores< e2.Scores;
 }
 }
//利用委托实现冒泡
class BubbleScores
 {
 public static 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;
  swapped = true;
  }
 }
 } while (swapped);
 }
 }
//调用
Student[] students={new Student("wyl", 100),#};
BubbleSorter.Sort(students, Student.CompareScores);
foreach(var student in students)
 Console.WriteLine(student);

3.匿名函数与lambda

3.1什么是匿名函数

匿名函数是一个“内联”语句或表达式,可在需要委托类型的任何地方使用。

可以使用匿名函数来初始化命名委托(无需取名字的委托),或传递命名委托(而不是命名委托类型,传递一个方法块,而不是委托类型)[callback的方式]作为方法参数。

MyDelegate funDelegate = delegate(string s) { Console.WriteLine(s); };
funDelegate ("this is anonymous delegate");

3.2.lambda

lambda表达式实际上是一个匿名函数。编译器在看到lambda之后会在类中自动定义一个新的私有方法。lambda必须匹配委托!其中lambda是从c#3.0后引用的

lambda的语法:

参数 => 方法体。

=>左边是要传入的参数,本例中是传入一个Int类型的变量,=>右边是具体的代码。

//如果不传递参数:
()=>Console.WriteLine("Hello World!")
//传递一个参数:
(int n)=>Console.WriteLine(n.ToString())
//或者去掉()和int 编译器会自己推断类型:
n=>Console.WriteLine(n.ToString())
//传递多个参数:
(int n ,int m)=>Console.WriteLine(n+m)
//或者编译器自己推断类型:
(n , m)=>Console.WriteLine(m+n)

4.综上:

1.委托类似于 C++ 函数指针。

2.委托允许将方法作为参数进行传递。

3.委托可用于定义回调方法。

4.委托可以链接在一起;多播。

5.方法不必与委托签名完全匹配。

以上就是c#基础知识---委托,匿名函数,lambda的详细内容,更多关于c# 委托,匿名函数,lambda的资料请关注我们其它相关文章!

时间: 2020-06-16

C#调用Win32的API函数--User32.dll

Win32的API函数是微软自己的东西,可以直接在C#中直接调用,在做WinForm时还是很有帮助的.有时候我们之直接调用Win32 的API,可以很高效的实现想要的效果. 代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace WindowsAPI { class CSharp_

C# ODP.NET 调用Oracle函数返回值时报错的一个解决方案

有人在社区问到:C#调用Oracle中自定义函数的返回值时,无法正常调用.但在PL/SQL中正常调用返回. 于是动手一试: 1.准备函数(Oralce 11g.2.0.0.4) CREATE OR REPLACE FUNCTION F_Update_Grade(v_UserID in Number) return nvarchar2 is V_Grade nVARCHAR2(20); begin V_Grade := '1205'; update TESTDB3 set Grade = V_Gr

C++/JAVA/C#子类调用父类函数情况总结

时间久了就容易记不清了,特留存备用查看 c++ 1.构造函数调用   常用初始化列表  或者显示调用 1.1同一个类中构造函数调用构造函数   尽量不要这样做,因为结果不确定!避免麻烦 可以把共用的代码封装成一个私有的成员函数,然后在构造函数内统一调用. 1.2子类构造函数调用基类构造函数 -----基类有默认构造函数时,可以在子类不写,则隐式调用 -----基类无/有默认构造函数时,在子类构造函数初始化列表处调用,则显示调用     基类类名(参数) class Base { public:

C#通过PInvoke调用c++函数的备忘录的实例详解

目前知道的情况被调用的C/C++函数只能是全局函数 不能调用类中的成员方法 被调用的C函数必须使用extern "C"包含,保证采用的导出函数名生成规则和.NET一致 函数调用约定通常使用WINAPI也就是__stdcall,.net默认也是__stdcall .net可以和c++同时用cdecl调用约定,这样可以支持可变参数个数 c函数必须使用__declspec(dllexport)前缀来导出 PInvoke assistant工具可以辅助生成C#和VB的引入声明,还可以查看常见的

详解c# 类的构造方法

一.构造方法 类的构造方法是类的成员方法的一种,它的作用是对类中的成员进行初始化操作.类的构造方法分为:     1.静态构造方法     2.实例构造方法 1.静态构造方法 类的静态构造方法是类的成员方法的一种,它的作用是对类中的静态成员进行初始化操作.下面请看代码实例: using System; namespace LycheeTest { class Test { //定义一个静态成员变量 private static int a; //定义静态构造函数 static Test() {

如何通过IL了解C#类的构造函数浅析

前言 我们知道,在调用构造函数时,C#会先对类中的字段.属性进行初始化操作.那么,问题来了,为什么在调用构造函数前会初始化类中的字段和属性呢?让我们一起通过ildasm来揭开构造函数的面纱吧. 需要反编译的C#代码如下: class CtorTester { private string _name; private int _age = 10; public int Age { get; set; } = 20; public CtorTester() { _name = "Name"

浅谈C# 构造方法(函数)

一.概括 1.通常创建一个对象的方法如图: 通过  Student tom = new Student(); 创建tom对象,这种创建实例的形式被称为构造方法. 简述:用来初始化对象的,为类的成员赋值. 2.构造方法特点 a.方法名与类名相同: b.没有返回值类型: c.必须要通过new的形式调用: 3.语法 访问修饰符 类名([参数]) { 方法体 } 二. 无参构造方法 1.在默认情况下,系统将会给类分配一个无参构造方法,并且没有方法体. 通过反编译工具看出: 我们也可以自定义一个无参构造方

浅谈Python中函数的参数传递

1.普通的参数传递 >>> def add(a,b): return a+b >>> print add(1,2) 3 >>> print add('abc','123') abc123 2.参数个数可选,参数有默认值的传递 >>> def myjoin(string,sep='_'): return sep.join(string) >>> myjoin('Test') 'T_e_s_t' >>>

浅谈JS封闭函数、闭包、内置对象

一.变量作用域指的是变量的作用范围,javascript中的变量分为全局变量和局部变量 1.全局变量:在函数之外定义的变量,为整个页面公用,函数的内部外部都可以访问. 2.局部变量:在函数内部定义的变量,只能在定义该变量的函数内部访问,外部无法访问.函数内部访问变量时,先在内部查找是否有此变量,如果有,就使用内部,如果没有,就去外部查找 二.封闭函数封闭函数是javascript中匿名函数的另外一种写法,创建一个一开始就执行而不用命名的函数. 1.一般函数的定义和执行函数 2.封闭函数的定义和执

浅谈PHP eval()函数定义和用法

eval() 函数把字符串按照 PHP 代码来计算. 该字符串必须是合法的 PHP 代码,且必须以分号结尾. 如果没有在代码字符串中调用 return 语句,则返回 NULL.如果代码中存在解析错误,则 eval() 函数返回 false. 语法 eval(phpcode) 参数 描述 phpcode 必需.规定要计算的 PHP 代码.  提示和注释 注释:返回语句会立即终止对字符串的计算. 注释:该函数对于在数据库文本字段中供日后计算而进行的代码存储很有用. 例子 <?php $string

浅谈python socket函数中,send与sendall的区别与使用方法

在python socket编程中,有两个发送TCP的函数,send()与sendall(),区别如下: socket.send(string[, flags]) 发送TCP数据,返回发送的字节大小.这个字节长度可能少于实际要发送的数据的长度.换句话说,这个函数执行一次,并不一定能发送完给定的数据,可能需要重复多次才能发送完成. 例子: data = "something you want to send" while True: len = s.send(data[len:]) if

浅谈使用splice函数对数组中的元素进行删除时的注意事项

使用splice函数对数组中的元素进行删除时的注意事项 删除值为c的元素: <script> var arr = new Array(); arr[0] = 'a'; arr[1] = 'b'; arr[2] = 'c'; arr[3] = 'c'; arr[4] = 'e'; for(var i=0; i<arr.length; i++){ if(arr[i] == 'c'){ arr.splice(i,1); i=i-1; // 必须对i减去1,否则后面的一个元素会被跳过去 } }

浅谈Python中函数的定义及其调用方法

一.函数的定义及其应用 所谓函数,就是把具有独立功能的代码块组织成为一个小模块,在需要的时候调用函数的使用包含两个步骤 1.定义函数–封装独立的功能 2.调用函数–享受封装的成果 函数的作用:在开发时,使用函数可以提高编写的效率以及代码的重用'' 函数: 函数是带名字的代码块,用于完成具体的工作 需要在程序中多次执行同一项任务时,你无需反复编写完成该任务的代码,而只需调用该任务的函数,让python运行其中的代码,你将发现,通过使用函数,程序编写,阅读,测试和修复都将更容易 1.定义函数 def

浅谈Vue render函数在ElementUi中的应用

vue的render函数在日常开发中被广泛应用,今天以ElementUI中的table表头重构为引,实际应用一下借助render函数实现表头搜索,不足之处请多多指教! 首先引入官方demo <el-table :data="tableData" style="width: 100%" :border="true"> <el-table-column prop="date" label="日期&quo

浅谈numpy中函数resize与reshape,ravel与flatten的区别

这两组函数中区别很是类似,都是一个不改变之前的数组,一个改变数组本身 resize和reshape >>> import numpy as np >>> a = np.arange(20).reshape(4,5) >>> a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) >>> a.reshape(2,1

浅谈C++ 虚函数

缘起 在上一篇文章中,测试代码2 中的 pBaseA->AA(); 输出的内容很"奇怪".其实,完全在情理之中.本文将简单探究一下 c++ 中的虚函数实现机制.本文主要基于 vs2013 生成的 32 位代码进行研究,相信其它编译器(比如,gcc)的实现大同小异. 先从对象大小开始 假设我们有如下代码,假设 int 占 4 字节,指针占 4 字节. #include "stdafx.h" #include "stdlib.h" #inclu