【精选译文】.NETFramework的每一个新版本都给我们带来了许多新特性,让.NET变得更加强大和易用使用,.NET4.0版当然也不例外。当我们关注个别新特性时,我们会看到微软正在C#和VB.NET之间相互学习,以实现“联合开发”的承诺。动态查找(C#中新引入的)正如我们前面提到的,C#添加了一个新的静态类型,称为动态。虽然它在很多情况下都可以工作,但不是很常见。您可以将动态类型视为支持惰性绑定的对象。dynamicCar=GetCar();//获取动态对象的引用Car.Model="Mondeo";//给属性赋值(alsoworksforfields)Car.StartEngine();//调用方法Car.Accelerate(100);//调用方法带参数dynamicPerson=Car["Driver"];//GettingwithanindexerCar["Passenger"]=CreatePassenger();//Settingwithanindexer在编译的时候基本忽略了动态对象的字段、属性和方法。也就是说,即使某个成员不可用,编译时也不会提示编译错误。因为该信息仅在运行时可用,所以.NET知道如何使用DLR来解析动态成员。出于性能方面的考虑,C#到目前为止仍然是一种静态类型的语言。新提供的动态类型并不意味着你可以完全放弃静态类型,它只是你不得不使用动态类型时可以使用的一个工具。另外别忘了,VB.NET已经支持动态查找(DynamicLookup)。关于如何在C#4.0中使用动态类型的更多信息,请参考之前发表的文章UsingDynamicTypesinC#4.0inVisualStudio2010。NET已经有一段时间了,现在C#终于也支持它们了。顾名思义,可选参数是可以选择性地传递给方法或构造函数的参数。如果您选择不传递参数,那么被调用的方法将使用先前定义的默认值。在C#中,要将一个方法参数变成一个可选参数,只需要给它赋一个默认值即可。publicvoidCreateBook(stringtitle="NoTitle",intpageCount=0,stringisbn="0-00000-000-0"){this.Title=title;this.PageCount=页数;这个.ISBN=isbn;您可以使用以下CreateBook();CreateBook("SomeBookTitle");CreateBook("SomeBookTitle",600);CreateBook("SomeBookTitle",600,"5-55555-555-5");这里注意reliable参数的位置很重要。在此示例中,标题必须作为第一个参数出现,页数作为第二个参数,ISBN作为第三个参数。如果您想调用CreateBook,但只将ISBN号作为参数传递,那么您有两种选择来实现此目的。第一个解决方案是创建一个以ISBN作为参数的重载方法。这个方法是很经典的方法,但是也比较麻烦。第二种方案是使用命名参数(namedparameter),比前一种方案简洁很多。命名参数允许您以任何顺序传递参数,只要您提供参数的名称即可。这时候可以调用如下形式的方法:CreateBook(isbn:"5-55555-5555-5");CreateBook("书名",isbn:"5-55555-5555-5");CreateBook(isbn:"5-55555-5555-5",title:"书名",pageCount:600);请注意,您可以先使用位置参数,然后使用我们上面演示的第二种方法,但是如果您使用命名参数(namedparameters),则必须一直使用它们。动态导入(C#中新引入)几乎所有通过COMAPI公开的接口都使用可变数据类型,这些数据类型以前在C#中由数据类型对象表示。在此之前,C#没有办法处理动态类型,所以对这些类型的处理就变成了各种数据类型之间的相互转换。但是现在C#支持动态类型,可以将COM组件导入为动态对象,这样就可以直接设置属性和调用方法,而不用显式转换对象类型。省略引用参数(RefParameter)(C#中新引入)调用COMAPI的另一个副产品是大量方法的参数必须通过引用传递。在大多数情况下,我们只想将一个值传递给方法而不关心它返回什么。即便如此,您仍然需要创建许多临时变量来保存结果。这种繁琐的工作可以交给实习生,让他们获得所谓的“实际工作经验”。在C#4.0中,你可以直接将参数值传递给COM,编译器会自动为你生成临时变量。这节省了开发人员的时间,也让实习生失去了很多所谓的“实际工作经验”。协方差和反方差(C#和VB.NET中的新增功能).NET4.0中解决了泛型最惊人的问题之一。以前,如果您有一个支持IEnumerable的对象,而您后来想将它传递给需要IEnumerable参数的方法,您会发现根本无法做到这一点。您必须生成一个新的支持IEnumerable的对象,用您从IEnumerable实例获得的字符串填充它,然后将它传递给该方法。我们都知道字符串是比对象更具体的类型,所以我们理所当然地认为List应该支持IEnumerable接口和IEnumerable。事实证明,编译器不会那样做。不过,在.NET4.0中,这个问题已经得到解决。因为现在泛型已经支持协变和变异。协变和逆变都与程序的类型安全和性能有关。粗略地说,协变就是可以认为一个对象是弱派生的(lessderived),只要在常规类型的参数前加上out关键字,就表示协变。协变类型仅限于输出位置,也就是说,它们仅作为调用方法或访问属性的结果出现。这些是协变类型唯一可以称为“安全”的地方,或者是唯一不需要在编译时进行额外类型检查的地方。在.NET4.0中,IEnumerable接口等效于IEnumerable,因为IEnumerable是协变的。这也意味着以下示例完全有效:IEnumerablestrings=GetStrings();IEnumerableobjects=字符串;反变是指一个对象可以被认为是更派生的,可以在普通参数中传入,在类型前加上in关键字来修饰表达式。逆变类型仅限于输入的位置,也就是说,它只能出现在方法的参数中或者必须具有“只写”属性。在.NET4.0中,IComparer接口现在是IComparer,因为IComparer发生了变化。这个概念不好理解,但是理解了它们的含义之后,在泛型转换时就可以省去很多麻烦。关于C#4.0中协变和求逆的详细介绍,请参考之前发布的C#4.0中泛型协变和求逆详解。NoneedforPrimaryInteropAssemblies(PrimaryInteropAssemblies)编译(C#和VB.NET中新引入)其中最广为人知的是MicrosoftOfficePrimaryInteropAssemblies。在开发期间,如果您的程序集包含对PIA的引用,则您必须使用PIA部署程序集,或提供有关如何获取PIA的说明。C#和VB.NET的新特性允许您将PIA直接嵌入到您自己的程序集中,大大简化了部署。PIA往往很大,因此将其全部包含在内会使您的程序集变得非常臃肿。幸运的是,编译器会优化选择只嵌入你实际使用的那部分PIA,当你只使用PIA的一小部分时,这可以有效地减少PIA的占用空间。#p#Anonymous方法支持(VB.NET中新引入)VB.NET新引入的另一个特性是内置(inline)或匿名(anonymous)方法。匿名方法这个名字很贴切,因为它允许你直接定义子方法(Subs)和函数,而不需要在你的类中添加另一个顶层(top-level)方法,这样这个方法就被隐藏了(即匿名)。匿名方法也可以访问它所在代码块的所有可用变量。这样,在定义匿名方法时,甚至不用参数也可以传入和返回值。您可以定义一个匿名函数,其中AddressOf关键字通常用于指向方法,因此它的最大用途可能是在事件处理中,如下例所示:DimMyTimerAsNewSystem.Timers.Timer(1000)DimSecondsAsInteger=0AddHandlerMyTimer.Elapsed,Sub()Seconds+=1Console.WriteLine(Seconds.ToString()&"secondsshaveelapsed")EndSubMyTimer.Start()Console.WriteLine("Pressanykeytoexit")Console.ReadLine()注意定义器的超时事件处理器是嵌入的,并且这个嵌入式方法直接访问在它之外定义的变量。您还可以定义内联函数:Dimf=Function(aAsInteger,bAsInteger)Returna+bEndFunctionDimx=10Dimy=20Dimz=f(x,y)如果内联函数在代码块的上下文中有意义,那确实非常使用方便,但使用后,很可能会影响程序的复用性。隐式续行(VB.NET中新引入的)看C#代码时,一眼就能看出语句的结束位置在哪里,因为它使用分号作为语句的结束符。VB也有语句结束符,不过它的结束符是回车,假定每条语句都在同一行。如果你想打破这个规范,你必须使用下划线来表示下一行是这个语句的延续。写过VB.NET程序的人应该会觉得这种方法既麻烦又影响代码的美观。DimtextAsString="Wouldn'titbenice"&_"Ifyoudidn'thaveto"&_"putanunderscoreto"&_"continuetothenextline?"好吧,现在我们不必再这样做了。VB.NET现在支持隐式续行。当编译器在一行中发现不完整的语句时,它会自动检查下一行的内容是否包含该语句的剩余部分。DimtextAsString="Wouldn'titbenice"&"Ifyoudidn'thaveto"&"putanunderscoreto"&"continuetothenextline?"&"亲爱的!现在你可以了!"如果你还喜欢怀旧的感觉,你仍然可以使用原来的显示声明方法,现在仍然可以使用该方法。而且有时我们可能不得不使用它,因为在某些情况下编译器可能无法确定下一行是否是续行。别担心,这种情况不会经常发生,如果发生编译器会通知你。简化的属性语法(VB.NET的新增功能)简化的属性语法是从C#引入VB.NET的另一个特性。通常属性定义如下所示:'FieldPrivate_nameAsString'PropertyPublicPropertyName()AsStringGetReturn_nameEndGetSet(ByValvalueAsString)_name=valueEndSetEndProperty现在可以缩短为:PublicPropertyName()asString这将代码行数从9减少到1好的。如果选择这种简化的写法,需要注意的一个问题是不能访问其值所在的区域,这会导致引用传递时出现问题。如果发生这种情况,您总是可以恢复正常写入或使用临时变量。数组类型推断(Arraytypeinference)和多数组(JaggedArrays)(VB.NET新引入)VB.NET现在支持数组类型推断和多数组定义语法。这意味着你在用初始值定义它时不必显式声明它的类型,编译器可以自动确定它的类型。例如:DimNumbers={1,1,2,3,5,8,13,21,34}当你看到这个数组的时候,你可以很快判断它是一个整数类型,现在编译器和我们一样准确正在做这个判断。DimNumbers={1,1,2,3,5.0,8,13,21,34}编译器看到上面的例子,会发现5.0不是整数,所以数组类型是double。类型判断也可以用于矩阵:DimNames={{"Sarah","Jane","Mary","Susan","Amanda"},{"Bob","Joe","Dustin","Richard","Nick"}}编译器可以推断出string()是上面例子的类型。在多阵列中,您可能会遇到一些问题。您可以将二维矩阵视为每行具有相等列数的矩阵。多数组每行的列数是可变的,所以和矩阵还是有些区别的。您可能认为可以像这样定义一个多重数组:DimNames={"Sarah","Jane","Mary","Susan","Amanda"},"Bob","Nick"}但您会发现编译器抛出错误“Arrayinitialiserismissing3elements”(Arrayinitialiserismissing3elements),这是因为编译器默认将其视为矩阵。如果你想定义一个多数组,那么只需将这些行用花括号括起来:DimNames={{"Sarah","Jane","Mary","Susan","Amanda"},{"Bob","Nick"}}现在编译器可以推断出它的类型是string()(),这是多数组的正确类型。From关键字(VB.NET新引入)说完了初始化,我们就不得不说说VB.NET中新引入的From关键字。当您创建字典、表格或其他由许多对象组成的对象时,您通常首先创建对象本身,然后用适当的项填充它。现在有了From关键字,就不用再重复调用Add方法了,它可以自动调用Add方法为我们填充列表。所以现在不要写这样的东西:DimColorsAsNewList(OfString)Colors.Add("Red")Colors.Add("Green")Colors.Add("Blue")把它缩减为:DimColorsAsNewList(OfString)From{"Red","Green","Blue"}毫无疑问,它实际上调用了Add方法,这意味着它可以作用于任何包含Add方法的对象。事实上,您甚至可以使用扩展方法来创建Add方法或重载Add方法,如果传入参数与方法声明匹配,From关键字将使用它们。在前面的示例中,List对象有一个只接受一个参数的Add方法,即要添加到表中的字符串。如果你有一个带有多个参数的Add方法,你可以像定义一个矩阵一样传入参数。下面的示例演示了如何将Add方法与Dictionary对象一起使用。DimColors2AsNewDictionary(OfString,String)From{{"Red","FF0000"},{"Green","00FF00"},{"Blue","0000FF"}}因为Dictionary的Add方法包含两个参数,key(key)和value(value),我们在From语句中传入参数时,必须两两传入一组参数。另外,在使用From关键字时要注意保持可读性。在某些特定情况下,您可能仍想回退到使用Add方法。【编者推荐】VisualStudio2010中使用C#4.0动态类型的VB.NET与C#的开发及动态语言运行时浅谈C#4.0中的动态类型与动态编程。NET并不意味着VB.NET或C#或更多的语言微软正在构建一个动态语言层以使.Net更具吸引力
