09.C#嘱托转换和匿名方法(五章5.1-5.4)

09.C#委托转换和匿名方法(五章5.1-5.4)

  今天将书中看的,自己想的写出来,供大家参考,不足之处请指正。进入正题。

  在C#1中开发web form常常会遇到使用事件,为每个事件创建一个事件处理方法,在将方法赋予给事件中,会使用new EventHandler(),不同的事件有各种不同的EventHandler的派生类的实例,因为我这里使用的时Console App,原理是一样的,且看

//定义一个委托
delegate void Printer();

static void Main(string[] args)
{
    Printer p = new Printer(Print1);
    p += new Printer(Print2);
    p += new Printer(Print3);
    p.Invoke();
    Console.ReadKey();
}

static void Print1()
{
    Console.WriteLine("print1");
}

static void Print2()
{
    Console.WriteLine("print2");
}

static void Print3()
{
    Console.WriteLine("print3");
}

  可以看到每次给p委托一个方法时,都要new Printer(),参数为要传入的方法,可以想象在不同的委托时,要用代码显式地创建各种委托,过于繁琐。而在C#2中支持从方法组到一个兼容委托类型的隐式转换,自己想当然的理解为C++中的复制构造函数,如Printer p = Print1其实就是调用了new Printer(Print1),代码如下。

1 Printer p = Print1;
2 p += Print2;
3 p += Print3;
4 p.Invoke();

  Printer p = Print1调用了Printer类的构造函数,而+=操作应该是Printer类型重载了+操作,用于两个Printer类相加,而方法组实现隐式转换,Print2和Print3隐式转换为Printer类的实例,C#2这样的操作减少了代码的输入,且更为直观,如"我只是把一个方法给到了一个对象,让它帮我执行,我才不管你要让传什么样的类型"。

  1. 泛型委托的协变性
  2. 委托返回的逆变性

  对于第一点,可以理解为要给委托一个方法,用这个方法创建的委托可以是另一个委托的派生类,如所有事件处理的基类是EventHandler,当一个事件需要传入一个方法,则可以使用这个方法来创建一个从EventHandler中派生的类的实例,不用事件我不会用代码表示,请大牛告知

  对于第二点,委托定义返回类型中,如果返回类型有派生类,如在实现的方法中返回其派生类,则可以使用该方法创建委托。

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  匿名方法,匿名方法使用delegate关键字,允许你指定一个内联委托实例的操作,匿名方法返回一个委托的实例。

  C#2中许多内建的泛型委托,如Action(T),Predicate<T>等等,则在实例化委托时可以使用匿名函数。如

1 Action<int> a = delegate (int x) { Console.WriteLine(x); };
2 Predicate<bool> b = delegate (bool x) { return x == true; };
3 a.Invoke(1);
4 b.Invoke(1 == 1);
5 a(2);
6 b(2 == 3);

  请注意匿名方法返回一个委托实例。如果只是单纯是只想处理一些无关于参数的事情,可以考虑省略参数。这让我想到一点就是在程序出错时,如果不记录参数,可以直接打印"出错了",而对于匿名函数,则可以省略参数。

1 System.Threading.Thread th = new System.Threading.Thread(delegate (object x) { });
2 System.Threading.Thread th2 = new System.Threading.Thread(delegate() { });

  其实上述的讲法是错的,其实很讨厌一些话,写了很多的东西,自己看得好像有点道理,然后突然告诉你"那些东西错误的观点",这次我也来使用一下。

  前面说过匿名函数返回一个委托的实例,我解理为匿名方法确实是一个方法,因为存在之前说过的隐式转换(也就是C++中的复制构造函数,或者单参数的构造函数),它返回一个符合new System.Threading.Thread()中一个合适的参数类型,所以我觉得参数是不可省略的,书中就是可以省略,其实只是System.Threading.Thread有两个重载版本而已,自己的想法,错的请大牛们指正,小弟不胜感激。

  请斧正。

 

2楼浩GE
另外楼主你看的书好像是只讲c# 2.0的?太旧了,建议看新一点的,c#都快出6.0了
1楼浩GE
引用Printer p = Print1调用了Printer类的构造函数,而+=操作应该是Printer类型重载了+操作,用于两个Printer类相加,说两个Printer类相加其实不太准确, 委托的+=操作其实是调用了Delegate的Combine方法(所有的委托都是继承Delegate的,Delegate的内部维护了一个Delegate数组,也就是委托链)。,引用Print2和Print3隐式转换为Printer类的实例,我觉得不应该称为隐式转换,称为语法糖或许更准确些,引用quot;我只是把一个方法给到了一个对象,让它帮我执行,我才不管你要让传什么样的类型quot;,说法不对,上面说了操作符+=其实是把委托对象“合并”了,也就是放进委托链里,最终调用时会迭代委托链依次执行。当然方法的签名需要和委托一致,引用前面说过匿名函数返回一个委托的实例,我解理为匿名方法确实是一个方法,匿名方法返回一个委托实例,这说法应该没错, 你针对什么委托类型使用匿名方法它就返回该委托类型的实例(签名需一致)。匿名方法确实是一个方法,这说法我个人觉得也对,因为你在针对委托使用匿名方法时,编译器内部其实会为你生成一个方法(必要时还会生成一个类,一般出现闭包什么的才会生成类),这个方法的实现就是匿名方法的实现,然后编译器根据该方法生成相应的委托返回。,我觉得你可以用ILDASM工具看看委托是怎么样的。也可以在代码中使用匿名方法编译然后再反编译生成代码,看看编译器帮你做了哪些事情,你应该会明白的更多。