C#学习笔记(1)-Delegates、Lambdas和Events

1.Delegates

①首先Delegate无法在Objective-C找到对应概念。
②Delegate首先是一个类,可以包含方法的地址,并且可包含多个方法。Delegate对方法进行了一层包装,从而可以实现C#的语言特性。C和C++中是方法地址,但并不安全,Delegate包装一层,所以更安全。
③Lambda表达式由delegate实现,Evnets也需要由delegate实现。
④Delegate比如可以用于多线程,用于泛型库的编程,用于Event的编程。
⑤Delegate继承自 System.MuticastDelegate,继承自 System.Delegate

1)Delegate的声明
public delegate void IntMethodInvoker(int x);

可以理解为delegate是一个Class类似的概念,delegate后面的方法和参数和返回值,表明了delegate保存的是什么类型的方法的地址。

2)Delegate的使用
private delegate string GetAString();
int x = 40;
GetAString firstStringMethod = new GetAString(x.ToString);
Console.WriteLine($"String is {firstStringMethod()}");

先定义delegate,然后new一个delegate对象,传入对象x的方法ToString(方法作为delegate对象的构造参数),最后调用实例化的delegate对象的执行方法,(),可以使用invoke调用执行。

其中

GetAString firstStringMethod = new GetAString(x.ToString);

可以缩写为

GetAString firstStringMethod = x.ToString;

理解上仍然需要知道是new了一个delegate对象。

3) Action <T> 和 Func <T> Delegates

Action用于定义没有返回值的Delegate,参数可以有多个

Func 用于定义有返回值的Delegate,参数可以有多个

主要目的:减少自己去定义Delegate。

比如定义一个比较大小的Delegate,用Func<T, T, bool>。

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;
                        swapped = true;
                    }
                }
            } while (swapped);
        }
    }

在Employee中实现Delegate定义的比较大小的方法

public static bool CompareSalary(Employee e1, Employee e2) =>
e1.Salary < e2.Salary;

然后调用时传入对应的Delegate方法的定义的实现即可。

BubbleSorter.Sort(employees, Employee.CompareSalary);
4) 多播Delegates

一般用于保存于Delegate中的方法依次执行,不保证有序,一般需要都是无返回值的。有返回值,只会返回最后一个执行的方法的返回值,意义不大。注意:如果一个方法报错,后续的方法都不会执行了。如果仍然想要报错后面的方法执行,则需要自己手写遍历调用。

Action<double> operations = MathOperations.MultiplyByTwo;
perations += MathOperations.Square;
perations -= MathOperations.Square;
5)匿名方法

定义:是一个代码块,可以传给delegate(用delegate包装)。用于方法只使用一次的情况。多次还是要自己去定义方法。很少用,因为有lambda表达式。

string mid = ", middle part,";
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"));

思考:delegate本质是包装了方法后的对象。并且可以存储和传递。在objective-c中找不到类似的概念。

2.Lambdas

1) Lambda表达式

匿名方法可以写为LAMBDA表达式,Lambda表达式本质是一个方法包装为了一个delegae。

string mid = ", middle part,"; 
Func<string, string> lambda = param => {
    param += mid;
    param += " and this was added to the string."; 
  return param;
};
Console.WriteLine(lambda("Start of string"));
2) Closure 闭包

定义:lambda表达式使用了其外部的变量。

闭包中引用的外部变量,在闭包执行时捕获其值。因为执行时才产生匿名类,此类copy外部的变量。类似于objective-C的block捕获,block本质也是一个类。原文如下:

Using the lambda expression and invoking the method creates an instance of the anonymous class and passes the value of the variable from the time when the call is made.

思考:C#的闭包还是和objective-c的闭包有很大差别,object-c的闭包可以定义__block来标记是否可以更改block外部的对象,C#没有这么细致的拆分。

3.Events

定义:Event通过delegate实现,提供订阅和发布机制。用处,比如button的点击事件。Events需要传递,第一个参数是发送者事件者本身,第二个是其他信息。此传递被包装为需继承EventArgs的类。

定义Event

public event EventHandler<CarInfoEventArgs> NewCarInfo;

等价于定义特殊的delegate

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs: EventArgs

等价于

private EventHandler<CarInfoEventArgs> _newCarInfo; 
public event EventHandler<CarInfoEventArgs> NewCarInfo {
    add => _newCarInfo += value;
    remove => _newCarInfo -= value; 
}

完整的例子如下

1) 定义传递的消息包装类,继承自EventArgs
① 定义消息
public class CarInfoEventArgs:EventArgs  
{
  public CarInfoEventArgs(string car) => Car = car;
    public string Car { get; }
}
2) 定义消息发布者,注意发布者的Invoke传递自己和消息。
public class CarDealer
{
  ② 用来保存方法
    public event EventHandler<CarInfoEventArgs> NewCarInfo; 

    public void NewCar(string car)
    {
        Console.WriteLine($"CarDealer,new car{car}");
        NewCarInfo?.Invoke(this,new CarInfoEventArgs(car));
    }
}
3) 定义消息订阅者,注意订阅的方法和发布的方法的结构一致,包括sender和消息
public class Consumer
{
    private string _name;
    public Consumer(string name) => _name = name;

    ③ 定义收到通知的处理方法
    public void NewCarIsHear(Object sender, CarInfoEventArgs e) 
    {
        Console.WriteLine($"{_name}: car{e.Car} is new");
    }
}
4) 建立发布者和订阅者的关联,注意订阅者的执行方法保存在发布者的delegate对象中。
public static void Main(string[] args)
{
    var dealer = new CarDealer();// 发布者
    var valtteri = new Consumer("Valtteri"); // 订阅者
  
  ④ 保存方法的delegate和收到通知的方法建立联系
    dealer.NewCarInfo += valtteri.NewCarIsHear; // 建立关联
    ⑤ 发送通知
  dealer.NewCar("Williams"); // 发布者发布

}

思考:发布订阅模式广泛应用于c#的各类应用中。建立发布订阅的流程项目objective-c较繁琐。objective-c只需要两个方法即可建立对象间的订阅和发布关系,并且不用特别定义传递的消息,消息可以直接是自定义的类。相对来说C#使用这种模型,就比较繁琐,需要标注的①②③④⑤四步,要写的代码也较多。这也不难理解Windowsphone为什么开发效率不高。

本文是对《Professional C# 7 and NET Core 2.0》第八章的读书笔记。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容