委托发展史(三)

通过C#2极大的简化了委托的使用。如果仅仅是为了简化事件的订阅以及增强可读性,这些技术确实已经足够了。

一、匿名类型
可通过使用 new 运算符和对象初始值创建匿名类型。
示例:
var v = new { Name = "Micro", Message = "Hello" };
var v = new[] {
    new { Name = "Micro", Message = "Hello" },
    new { Name = "Soft", Message = "Wold!" }
};
匿名类型通常用在查询表达式的 select 子句中,以便返回源序列中每个对象的属性子集。
var Query = from p in v select new { p.Name };
foreach (var o in Query)
{
    Console.WriteLine(o.Name);
}
可以查找对象
IEnumerable<v> results = people.Where(delegate(v p) { return p.Name == "Micro"; });

但是,C#2中的委托仍然过于臃肿:一页充满匿名方法的代码,读起来真让人难受,你也肯定不愿意经常在一个语句中放入多个匿名方法吧。

二、匿名方法
要将代码块传递为委托参数 例如:
点击事件
button1.Click += delegate(System.Object o, System.EventArgs e)
{
    System.Console.WriteLine("Hello");
};
金沙官网线上,this.Loaded += delegate
{
    InitializeEvent();
};

C#3可以说是一个工业革命。

加载事件
this.Loaded += (sl, el) =>
{
    System.Console.WriteLine("Hello");
    this.button1.Click += (sender, e) =>
    {
        System.Console.WriteLine("Wold!");
    }
}

*作为委托的Lambda表达式

从许多方面Lambda表达式都可以看做是C#2的匿名方法的一种演变。

匿名方法能做到的几乎一切事情都可以用Lambda表达式来完成,另外,几乎所有情况下,Lambda表达式都更易读,更紧凑。

从最显而易见的方面看,两者并无多大区别--只是Lambda支持许多简化语法使他们在常规条件下显得更简练。

与匿名方法相似,Lambda表达式有特殊的转换规则:表达式的类型本身并非委托类型,但它可以通过多种方式隐式或显式转换成一个委托实例。

匿名函数这个术语同时涵盖了匿名方和Lambda表达式--,在很多情况下,两者可以使用相同的转换规则。

慢慢来看这一场工业革命吧。。。

匿名方法与线程
System.Threading.Thread thread = new System.Threading.Thread(delegate(j)
{
    System.Console.WriteLine("Hello");
});
thread.Start();

*Func<...>委托类型简介

在.NET3.5的System命名空间中,有5个泛型Func委托类型,

Func并无特别之处——只是他提供了一些好用的预定义泛型类型,在很多情况下能帮助我们处理问题。

每个委托签名都获取0~4个参数,其类型用类型参数来指定。最后一个类型参数用作每种情况下的返回类型。

通俗讲就是这个Func是一个有返回值委托类型。

看一下.NET3.5所有Func委托的签名:

public delegate TResult Func<TResult> ();
public delegate TResult Func<T,TResult> (T arg);
public delegate TResult Func<T1,T2,TResult> (T1 arg1,T2 arg2);
public delegate TResult Func<T1,T2,T3,TResult> (T1 arg1,T2 arg2,T3 arg3);
public delegate TResult Func<T1,T2,T3,T4,TResult> (T1 arg1,T2 arg2, T3 arg3, T4 arg4);

例如,Func<string,double,int>  等价于以下形式的委托类型。

public delegate int TestDelegate(string arg1, double arg2);

当你想返回void时,也就是无返回值,可使用Action<...>系列委托,其功能相似。

Action在.Net2.0中就有了,但其他都是.NET 3.5新增的。如果4个参数还嫌不够,.NET 4将Action与Func家族扩展为拥有16个参数。

因此Func<T1,..., T16 , TResult >拥有17个参数类型。

例如,我们需要获取一个stirng参数,并返回一个int,所以我们将使用Func<string,int>。

System.Threading.ThreadPool.QueueUserWorkItem((s) =>
{
    Action f = () =>
    {
        System.Console.WriteLine("Wold!");
    };
}

*转换到Lambda表达式

Func<string, int> returnLength;
returnLength = delegate (string text) { return text.Length; };
Console.WriteLine(returnLength("Hello"));

最后会输出"5",预料之中。

注意上面的代码,returnLength的声明与赋值是分开的,否则一行可能放不下——除此之外,这样还有利于对代码的理解。所以,我们将它转换成Lambda表达式

Lambda表达式最冗长的形式是:

(显式类型的参数列表) => { 语句 }

=>这个是C#3新增的,他告诉编译器我们正在使用一个Lambda表达式。Lambda表达式大多数时候都和一个返回非void的委托类型配合使用——如果不反悔一个结果,语法就不像现在这样一目了然。

这个版本包含显式参数,并将语句放到大括号中,他看起来和匿名方法非常相似。

Func<string, int> returnLength;
returnLength = (string text) => { return text.Length; };
Console.WriteLine(returnLength("Hello"));

在阅读Lambda表达式时,可以将=>部分看成"goes to"。

匿名方法中控制返回语句的规则同样适用与Lambda表达式:不能从Lambda表达式返回void类型;

如果有一个非void的返回类型,那么每个代码路径都必须返回一个兼容的值。

到目前为止,使用Lambda表达式并没有节省多大空间,或使代码变得容易阅读。

使委托与匿名方法关联
delegate void DEL(string s);
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    DEL p = delegate(string j)
    {
        System.Console.WriteLine(j);
    };
    p("Hello");
}

*用单一表达式作为主体

我们目前使用一个完整的代码块来返回值,这样可以灵活地处理多种情况——可以在代码块中放入多个语句,可以执行循环,可以从代码块中不同位置返回。。。等等

这和匿名方法是一样的。

然而,大多数时候,都可以用一个表达式来表示整个主体,该表达式是Lambda结果。(意思就是,一条语句就可以解决的事)

这些情况下,可以指定那个表达式,不用大括号;不使用return语句,也不添加分号,格式随即变成:

(显式类型的参数列表) => 表达式

在我们的例子中,就变成了——

(string text) => text.Length

现在已经开始变得简单了,接着来考虑一下参数类型。编译器已经知道Func<string,int>的实例获取单个字符串,所以只需命名那个参数就可以了。

感觉还是得分两行来声明跟赋值啊。。。

三、Func,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的委托
Func至少0个参数,至多16个参数,根据返回值泛型返回。必须有返回值,不可void

本文由金沙官网线上发布于编程,转载请注明出处:委托发展史(三)

您可能还会对下面的文章感兴趣: