游戏开发论坛

 找回密码
 立即注册
搜索
查看: 1856|回复: 0

.NET 3.5新特性2 wxh zt

[复制链接]

66

主题

108

帖子

112

积分

注册会员

Rank: 2

积分
112
发表于 2009-2-23 00:01:00 | 显示全部楼层 |阅读模式

对象初始化器实际上利用了编译器对对象中对外可见的字段和属性进行按序赋值。

对象初始化器允许只给一部分属性赋值,包括internal访问级别

对象初始化器可以结合构造函数一起使用,并且构造函数初始化先于对象初始化器执行。

集合初始化器会对初始化器中的元素进行按序调用ICollection<T>.Add(T)方法,所以只有具有Add方法的类才可以使用这种方法添加一个元素,例如ArrayList等,例如HashTable,字典等就不支持这种添加方式,因为其存在key,value两个值。

注意对象初始化器和集合初始化器中成员的可见性和调用顺序。

对象与集合初始化器同样是一种编译时技术。



扩展方法(Extension Methods)

往往我们需要对CLR类型进行一些操作,但苦于无法扩展CLR类型的方法,只能创建一些helper方法,或者继承类。我们来修改上面的User类:



public class User

{

public int Id { get; set; }

public string Name { get; set; }

public int Age { get; set; }

public string Read()

{

return "Id:" + Id + "姓名:" + Name + "年龄:" + Age;

}

}然后调用



var user = new { Id = 1, Name = "tony", Age = 21 };

var str = user.Read();现在有了扩展方法就方便多了。



扩展方法允许开发人员往一个现有的CLR类型的公开契约(contract)中添加新的方法,而不用生成子类或者重新编译原来的类型。扩展方法有助于把今天动态语言中流行的对duck typing的支持之灵活性,与强类型语言之性能和编译时验证融合起来。

扩展方法是可以通过使用实例方法语法调用的静态方法。效果上,使得附加的方法扩展已存在类型和构造类型成为可能。他可以对现有类功能进行扩充,从而使该类型的实例具有更多的方法(功能)。

扩展方法允许我们在不改变源代码的情况下扩展(即添加不能修改)现有类型中的实例方法。



扩展方法给我们一个怎样的思路呢?我们一步一步做一下!

首先声明扩展方法:通过指定关键字this修饰方法的第一个参数。注意扩展方法仅可声明在静态类中。扩展方法具备所有常规静态方法的所有能力,可以使用实例方法语法来调用。接着就可以调用扩展方法了。下面通过一个具体的实例分析一下:

例如我们要检查一个字符串变量是否是合法的电子邮件地址?在.Net2.0框架下像这样:



var email = "tony_wanghongchen@hotmail.com";

if (EmailValidator.IsValid(email))

{

Response.Write("tony提示:这是一个正确的邮件地址");

}而使用扩展方法的话,我可以添加"IsValidEmailAddress()"方法到string类本身中去,该方法返回当前字符串实例是否是个合法的字符串。



if (email.IsValidEmailAddress())

{

Response.Write("tony提示:这是一个正确的邮件地址");

}我们是怎么把这个IsValidEmailAddress()方法添加到现有的string类里去的呢?先定义一个静态类,再定义"IsValidEmailAddress"这个静态的法来实现的。



public static class Extensions//静态类

{

public static bool IsValidEmailAddress(this string s)

//静态方法和this

{

Regex regex = new Regex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");

return regex.IsMatch(s);

}

}注意,上面的静态方法在第一个类型是string的参数变量前有个"this"关键词,这告诉编译器,这个特定的扩展方法应该添加到类型为"string"的对象中去。然后在IsValidEmailAddress()方法实现里,我可以访问调用该方法的实际string实例的所有公开属性/方法/事件,取决于它是否是合法电子邮件地址来返回true/false。



扩展方法不仅能够应用到个别类型上,也能应用到.NET框架中任何基类或接口上。即可用于整个.NET框架丰富的可组合的框架层扩展。



扩展方法要点

扩展方法的本质为将实例方法调用在编译期改变为静态类中的静态方法调用。事实上,它确实拥有静态方法所具有的所有功能。

扩展方法的作用域是整个namespace可见的,并且可以通过using namespace来导入其它命名空间中的扩展方法。



扩展方法的优先级:现有实例方法优先级最高,其次为最近的namespace下的静态类的静态方法,最后为较远的namespace下的静态类的静态方法。



扩展方法是一种编译时技术,注意与反射等运行时技术进行区别,并慎重使用。

Lambda表达式和Lambda表达式树 (Lambda Expression and Lambda Expression Trees)

Lambda表达式

我们从"所有字符串查找包含tony子字符串"说起。在C# 2.0中,匿名方法允许我们以内联的方式来实现委托实例,它提供强大的函数式编程语言,但是标记显得相当的冗长和带有强制性。我们使用C# 2.0 中的匿名方法查找,代码如下:



var inString = list.FindAll(delegate(string s)

{ return s.Indexof("tony") >= 0; });现在可以使用C# 3.0带来的Lambda表达式允许我们使用一种更接近人的思维、更自然的方式来实现类似于匿名方法同样的效果,看下面的代码多么简洁:



var inString = list.FindAll(s => s.Indexof("tony") >= 0);Lambda表达式格式:(参数列表)=>表达式或语句块

具体意义:定义Lambda接受参数列表,运行表达式或语句块返回表达式或语句块的值传给这个参数列表。



Lambda表达式参数类型可以是隐式类型或显式类型。在显式列表中,每个参数的类型是显式指定的,在隐式列表中,参数的类型由Lambda表达式出现的语境自动推断类型。

Lambda表达式的参数列表可以有一个或多个参数,或者无参数。在有单一的隐型参数的lambda表达式中,圆括号可以从参数列表中省略。

例如:



(x, y) => x * y;//多参数,隐式类型=>表达式

x => x * 10;//单参数,隐式类型=>表达式

x => { return x * 10; }; //单参数,隐式类型=>语句块

(int x) => x * 10;//单参数,显式类型=>表达式

(int x) => { return x * 10; };//单参数,显式类型=>语句块

() => Console.WriteLine(); //无参数下面看这个例子:

在前面的帖子中,我们写了一个User类及增加了2个人,接下来,我们使用由LINQ提供的新的Where和Average方法来返回集合中的人的一个子集,以及计算这个集合中的人的平均年龄:



List<User> user = new List<User>{

new User{Id=1,Name="tony",Age=21},

new User{Id=2,Name="tony",Age=22},

};

//获取特定人时所用的过滤条件,p参数属于User类型

var results = user.Where(p => p.Name == "tony").ToList();

//用User对象的Age值计算平均年龄

var average = user.Average(p => p.Age);



LINQ,语言级集成查询(Language INtegrated Query)



经过了最近 20 年,面向对象编程技术( object-oriented (OO) programming technologies )在工业领域的应用已经进入了一个稳定的发展阶段。程序员现在都已经认同像类(classes)、对象(objects)、方法(methods)这样的语言特性。考察现在和下一代的技术,一个新的编程技术的重大挑战开始呈现出来,即面向对象技术诞生以来并没有解决降低访问和整合信息数据(accessing and integrating information)的复杂度的问题。其中两个最主要访问的数据源与数据库( database )和 XML 相关。



LINQ 提供了一条更常规的途径即给 .Net Framework 添加一些可以应用于所有信息源( all sources of information )的具有多种用途( general-purpose )的语法查询特性( query facilities ),这是比向开发语言和运行时( runtime )添加一些关系数据( relational )特性或者类似 XML 特性( XML-specific )更好的方式。这些语法特性就叫做 .NET Language Integrated Query (LINQ) 。



包含 DLinq 和 XLinq



C#3.0 LINQ 查询语法

首先来看一个很简单的LINQ查询例子,查询一个int 数组中小于5的数字,并按照大小顺序排列:

class Program

{

static void Main(string[] args)

{

int[] arr = new int[] { 8, 5, 89, 3, 56, 4, 1, 58 };

var m = from n in arr where n < 5 orderby n select n;

foreach (var n in m)

{

Console.WriteLine(n);

}

Console.ReadLine();

}

}

上述代码除了LINQ查询语法外,其他都是我们所熟悉的语法,而LINQ查询语法跟SQL查询语法很相似,除了先后顺序。



Q:为何 LINQ 查询语法是以 from 关键字开头的,而不是以 select 关键字开头的?select 开头这种写法跟SQL的写法更接近,更易懂呀?

A:简单来说,为了IDE的智能感知(InteliSence)这个功能,select 关键字放在后面了。

编程语言以 select 开头写LINQ查询语法不是没出现过,你如果使用过2005年的VB9 CTP 版本,那时候VB9的LINQ查询语法就是 select 关键字在前面,但是 select 关键字在前面,在做智能感知(InteliSence)时候就很头大。经过微软IDE组的权衡,确定了把 from 关键字放在最前面。



我们再来看一个稍稍复杂的LINQ查询:

在我们罗列的语言字符串中,我们希望按照字符长短,分类罗列出来,实现代码如下:

static void Main(string[] args)

{

string [] languages = {"Java","C#","C++","Delphi","VB.net","VC.net","C++ Builder","Kylix",&quoterl","Python"};

var query = from item in languages

orderby item

group item by item.Length into lengthGroups

orderby lengthGroups.Key descending

select lengthGroups;

foreach (var item in query)

{

Console.WriteLine("strings of length ",item.Key);

foreach (var val in item)

{

Console.WriteLine(val);

}

}

Console.ReadLine();

}

其中的 into 关键字表示将前一个查询的结果视为后续查询的生成器,这里是跟 group by一起使用的。

LINQ中的Group by不要跟 SQL 中的Group by 混淆,SQL 由于是二维结构,Group by 的一些逻辑受二维结构的约束,无法象 LINQ 中的Group by 这么灵活。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-20 06:55

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表