C#高级

93 阅读6分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。


提示:以下是本篇文章正文内容,下面案例可供参考 目标

1、扩展方法与yield关键字

2、隐式类型与匿名类型【重点】

3、Lambda表达式【重点】【难点】

4、委托【重点】【难点】

知识点讲解

一、C#扩展方法

1.1、作用(why)

便于向已经存在的类添加新方法,而无需创建新的派生类型。尤其适合系统类和第三方类库的类扩展新方法

1.2、如何实现(how)

A、添加包含扩展方法的静态类,此类必须对客户端代码可见(可访问性public )

public static class StringExtend { }

B、在静态类添加一个静态方法(扩展方法),静态方法可访问性与所在类的可访问性一致

public static class StringExtend {//static 表示程序一运行就执行这个类里面的代码
  public static int WordCount(this string str) //关键在于this关键字 表示将扩展方法添加到this指向的类型,str表示这种类型的一个实例
  {
   return str.Split(new char[] { ' ' }).Count();
  }
}

注:

1、静态类静态方法

2、扩展方法的第一个参数是指定方法所操作的类型、此参数前面必须加上this修饰符

C、调用扩展方法

第一步:添加using,引用包括扩展方法的类的命名空间

第二步:扩展方法的调用与调用类型的实例方法一样。

string sayhello="hello how are you"
sayhello.WordCount();

二、隐式类型与匿名类型

2.1、隐式类型

2.1.1、概念(what)

未明确指明变量的类型,编译器可以根据变量的初始值“推断”变量的类型,即初始值决定类型

2.1.2、如何实现(how)

var 变量 = 初始值;  //var 相当于标签 可以装任何东西

(1)必须初始值。

eg:var num;// 错误没初始值,无法推断变量num的类型

(2)赋值类型必须与初始值类型相同。

 eg:var num = 1;// 推断类型为int 
             num = “1”;// 错误 字符串类型与int类型冲突

2.2、匿名类型

2.2.1、概念(what)

没有名称类型

2.2.3、作用(why)

无需首先显式定义一个类型,提供了一种方便的方法,可用来将一组只读属性封装到单个对象中

2.2.4、如何实现(how)

(1)匿名类

//对比 class Student { public int ID{get;set;} public string Name{get;set;} public int Age{get;set;} }
var s= new { ID = 1, Name = "战三",Age = 25 }; 

(2)匿名方法。没有名称只有主体的方法。常用在委托,它的调用方式是通过委托来调用,所以创建也是通过委托来创建,可以形象的理解为封装到了委托中

delegate (参数列表 ){ 方法体 };

三、lambda表达式

3.1、概念(what)

是一个匿名方法,即没有方法名的方法。c#中的lambda表达式使用lambda运算符“=>”,读为“goes to”

3.2、如何实现(how)

语法:(形参数列表)=> { 方法体 }

(string x) => { Console.WriteLine("你好:" + x);}

(1)如果没有形参。()不能省略

(2)如果只有一个形参。()可省略

(3)如果大于一个参数,()不能省略

(4)如果方法体只有一条语句,{}可省略

四、委托

委托一件事情,让别人去做(买中华)

4.1、概念(what)

委托是一种数据类型(用户自定义的类型),和类是同级别的,我们可以直接将delegate看着为class,区别为class里存放的是一系列方法,属性,字段,事件,索引。而delegate里存放的是一系列具有相同类型参数和返回回类型的方法的地址。可以看着为储存方法的载体。调用委托时,此委托的所有方法都将被执行。

(1)自定义数据类型(相当于class)

(2)存储方法的载体(存储的是一些列方法(方法的参数类型和返回类型与委托相同)的地址)

(3)调用委托,委托的所有方法执行

4.2、作用(why)

提高程序的可扩展性

4.3、适用场合(whee)

(1)特别用于实现事件和回调方法

(2)使用委托将方法作为参数传递给其他方法 (具有多个相似行为或者方法的时候,其实就相当于一个约束或规范)

4.4、如何实现(how)

A、先声明一个委托(声明一种行为)

语法:访问修饰符 delegate 返回数据类型 委托名称 (参数列表)

//我发表买中华的委托 返回数据类型bool表示是否买 money 钱
public delegate bool BuyZH(int money);

注:委托放在命名空间 或者类里面 ,不能放在方法里面

B、实现委托并调用

第一种:实例化

语法:委托名 实例化名 = new 委托名(实现方法名); //实现方法是静态方法

static void Main(string[] args){//程序的入口
  BuyZH buyJJ1 = new BuyZH(BuyJJ);
  Console.WriteLine(buyJJ1(1));
  BuyZH buyXJ = new BuyZH(BuyXJ);//BuyXJ是一个静态的方法名
  Console.WriteLine(buyXJ(20));;//调用 通过委托的实例对象名
}
public static bool BuyJJ(int money){//买中华 积极
  Console.WriteLine("积极的买中华");
  return money >= 0;
}
public static bool BuyXJ(int money){//买中华 消极
  Console.WriteLine("消极的买中华");
  return money >= 60;
}

第二种:方法引用

语法:委托名 实例化名 = 实现方法名; //实现方法是静态方法

static void Main(string[] args){//程序的入口
  BuyZH buyJJ = BuyJJ;
  Console.WriteLine(buyJJ(10));;//调用
}

第三种:匿名方法

语法:委托名 实例化名 =delegate(方法参数){方法体};

BuyZH buyXJ = delegate (int money) { return money > 50; };
Console.WriteLine(buyXJ (10));//调用

第四种:lamda表达式实例化(重点)

语法:委托名 实例化名 = (参数列表) => { 方法体 };

BuyZH buyXJ = (int money) => { return money > 50; };
Console.WriteLine(buyXJ (10));//调用

(1)Lambda 包含的参数数量必须与委托类型包含的参数数量相同;

(2)Lambda 中的每个输入参数必须都能够隐式转换为其对应的委托参数;

(3)Lambda 的返回值(如果有)必须能够隐式转换为委托的返回类型

4.5、多播委托(组播)

what(概念):多个相同类型的委托通过+运算符组合一起形成方法调用列表

注:只有相同类型的委托可被合并

how(如何实现):

BuyZH buy= new BuyZH(BuyXJ);
buy+=new BuyZH(BuyJJ);
buy(50);//调用

4.6、委托作为方法参数

委托可以把一个方法作为参数代入另一个方法。委托可以理解为指向一个函数的引用。

//声明一个委托  (占位符)
public delegate int GetMoney(); //委托名 =占位符名称
public class User
{
//用户取钱的方法
  public int Buy(GetMoney getMoney)
  {
    Console.WriteLine("用户开始取钱啦");
    return getMoney();//调用委托
  }
}

综合案例:(1)算数运算 (2)银行取钱的用例

问: 事件是不是一种委托?是,是一种特殊的委托