皮皮网

【跨年源码】【优秀的js源码阅读】【vue2.7源码解析】ienumerable源码

时间:2024-11-29 23:58:39 分类:焦点 来源:开源ace 源码分享

1.MASA Framework源码解读-01 MASAFacotry工厂设计(一个接口多个实现的最佳姿势)
2.Eval()和Bind()的区别
3.七爪源码:C# 中的扩展方法
4.C#-Linq源码解析之DefaultIfEmpty
5.谁给简单介绍一下C#?

ienumerable源码

MASA Framework源码解读-01 MASAFacotry工厂设计(一个接口多个实现的最佳姿势)

       闲来无事,偶然接触到了MASA Framework,此框架是MASA Stack系列中专门用于构建web系统的开源框架。通过在几个小型项目中的应用,我发现它确实拥有诸多优点。为深入理解其内部结构和设计思路,跨年源码我决定详细阅读MASA Framework的源代码,并记录整个阅读过程。如有任何错误或疑问,还请各位指正。

       MASA Framework是一个功能全面且易于扩展的框架,主要由三个部分组成:BuildingBlocks(抽象层)、Contrib(BuildingBlocks的实现)以及Utils(工具库)。官方将BuildingBlocks称为构建块,实际上,优秀的js源码阅读这个层将日常开发中频繁使用到的功能抽象出来,如多租户、多语言、仓储、配置中心等,形成易于替换的接口,大大提高了框架的灵活性和可扩展性。

       MASA Framework包含个主要模块,几乎涵盖了日常开发所需的所有组件,从基础服务到高级功能应有尽有。这些模块协同工作,共同构建了一个强大且功能丰富的框架。

       让我们从MASA Framework的核心设计——构建工厂(MasaFactory)开始探讨。构建工厂在框架中起着至关重要的vue2.7源码解析作用,它负责通过配置选项来创建不同实现的实例。在实际项目中,构建工厂设计用于解决接口具有多种实现时的依赖注入问题,比如在面对多实现的场景时,如何优雅地注入并使用特定的实现类。以下是构建工厂解决多实现问题的具体步骤:

       首先,通过下载MASA Framework的源码(地址:github.com/masastack/MA...)进行研究。我们首先关注的是Masa.BuildingBlocks.Data.Contracts类库的设计。MASA Framework的构建工厂通过选项配置,允许为接口的每个实现类指定一个简短的名称。根据传入的不同名称,构建工厂类的Create方法能够创建对应的实例。

       通过使用MASA Framework的构建工厂,我们能够轻松地创建与特定名称对应的支付系统源码开发流程面单消息转换类,而无需依赖于IEnumerable集合进行复杂的筛选。这种方法在实现多实现场景时明显更加直观且高效。

       以物流面单申请为例,不同销售订单对应不同的商家店铺,而每个商家店铺可能选择不同的物流商。利用MASA Framework构建工厂实现不同物流商的面单申请,不仅简化了开发过程,而且在使用层面保持了无感的效果。

       总结而言,MASA Framework提供了强大的构建工厂设计,以解决多实现接口的依赖注入问题,简化了开发流程。这个设计不仅限于构建工厂模块,其他模块同样采用了类似的监控主机源码怎么查看设计理念,允许用户根据需要替换官方实现或结合自定义实现,以适应不同场景和需求。

       MASA Framework的其他模块同样采用了构建工厂的设计,用户既可以替换官方实现,也可以在程序内同时共存官方实现和自定义实现。例如,Service Caller模块不仅支持使用dapr的服务调用,还提供了HTTP服务调用等选项。

Eval()和Bind()的区别

       Eval(

       "

       ")和Bind(

       "

       ") 这两种一个单向绑定,一个双向绑定

       bind是双向绑定,但需数据源可更改才能用

       ASP.NET

       2.0改善了模板中的数据绑定操作,把v1.x中的数据绑定语法DataBinder.Eval(Container.DataItem,

       fieldname)简化为Eval(fieldname)。Eval方法与DataBinder.Eval一样可以接受一个可选的格式化字符串参数。缩短的Eval语法与DataBinder.Eval的不同点在于,Eval会根据最近的容器对象(例如DataListItem)的DataItem属性来自动地解析字段,而DataBinder.Eval需要使用参数来指定容器。由于这个原因,Eval只能在数据绑定控件的模板中使用,而不能用于Page(页面)层。当然,ASP.NET

       2.0页面中仍然支持DataBinder.Eval,你可以在不支持简化的Eval语法的环境中使用它。

       ä¸‹é¢çš„例子演示了如何使用新的简化的Eval数据绑定语法绑定到DataList数据项模板(ItemTemplate)中的Image、Label和HyperLink控件。

       ï¼œasp:DataList

       ID=

       "DataList1

       "

       RepeatColumns=

       "5

       "

       Width=

       "

       "

       runat=

       "server

       "

       DataSourceID=

       "ObjectDataSource1

       ">

       ã€€ï¼œItemTemplate>

       ã€€ã€€ï¼œasp:HyperLink

       ID=

       "HyperLink1

       "

       runat=

       "server

       "

       NavigateUrl=

       '<%#

       Eval(

       "PhotoID

       ",

       "PhotoFormViewPlain.aspx?ID={ 0}

       ")

       %>

       '>

       ã€€ã€€ï¼œasp:Image

       ID=

       "Image1

       "

       Runat=

       "server

       "

       ImageUrl=

       '<%#

       Eval(

       "FileName

       ",

       "images/thumbs/{ 0}

       ")

       %>

       '

       /></asp:HyperLink>

       ã€€ã€€ï¼œasp:Label

       ID=

       "CaptionLabel

       "

       runat=

       "server

       "

       Text=

       '<%#

       Eval(

       "Caption

       ")

       %>

       '

       />

       ã€€ï¼œ/ItemTemplate>

       ï¼œ/asp:DataList><br

       />

       ï¼œasp:ObjectDataSource

       ID=

       "ObjectDataSource1

       "

       runat=

       "server

       "

       TypeName=

       "DataComponentTableAdapters.PhotosTableAdapter

       "

       SelectMethod=

       "GetPhotosForAlbum

       ">

       ã€€ã€€æ•°æ®ç»‘定也可以作为控件的主题定义(theme

       definition)的一部分,这样我们就可以通过改变主题来随意地改变模板化控件的布局和外观。但是Theme(主题)模板中只能使用Eval(或者后面讨论的Bind)。绑定到任意的用户代码是被禁止的。

       --------关注----------

       å¸¸è§ç»‘定格式,不过他们的性能有区别。

       <%#

       DataBinder.Eval(Container.DataItem,

       "[n]")

       %>

       <%#

       DataBinder.Eval(Container.DataItem,

       "ColumnName")

       %>

       <%#

       DataBinder.Eval(Container.DataItem,

       "ColumnName",

       null)

       %>

       <%#

       DataBinder.Eval(Container,

       "DataItem.ColumnName",

       null)

       %>

       <%#

       ((DataRowView)Container.DataItem)["ColumnName"]

       %>

       <%#

       ((DataRowView)Container.DataItem).Row["ColumnName"]

       %>

       <%#

       ((DataRowView)Container.DataItem)["adtitle"]

       %>

       <%#

       ((DataRowView)Container.DataItem)[n]

       %>

       <%#

       ((DbDataRecord)Container.DataItem)[0]

       %>

       <%#

       (((自定义类型)Container.DataItem)).属性.ToString()

       %>(如果属性为字符串类型就不用ToString()了)

       ä¸Šé¢è¿™ä¸‰ä¸ªæ€§èƒ½æœ€å¥½ã€‚

       //显示二位小数

       //<%#

       DataBinder.Eval(Container.DataItem,

       "UnitPrice",

       "${ 0:F2}")

       %>

       //{ 0:G}代表显示True或False

       //

       //

       <asp:Image

       Width=""

       Height=""

       Border="0"

       runat="server"

       //

       AlternateText='<%#

       DataBinder.Eval(Container.DataItem,

       "Discontinued",

       "{ 0:G}")

       %>'

       //

       ImageUrl='<%#

       DataBinder.Eval(Container.DataItem,

       "Discontinued",

       "~/images/{ 0:G}.gif")

       %>'

       />

       //

       //转换类型

       ((string)DataBinder.Eval(Container,

       "DataItem.P_SHIP_TIME_SBM8")).Substring(4,4)

       { 0:d}

       æ—¥æœŸåªæ˜¾ç¤ºå¹´æœˆæ—¥

       { 0:yyyy-mm-dd}

       æŒ‰æ ¼å¼æ˜¾ç¤ºå¹´æœˆæ—¥

       { 0:c}

       è´§å¸æ ·å¼

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

       åœ¨æœ¬ç« å‰é¢ï¼Œæˆ‘们在模板上下文中遇到过表达式以及Eval方法。Eval方法是一种定制运算符,在数据绑定表达式用来方法所绑定的数据项上的公共属性。前文所用的Eval方法是一个ASP.NET

       2.0才支持的特征,如果在ASP.NET

       1.x应用程序中使用,则会产生一个编译错误。对于ASP.NET的所有版本,我们可以使用一个在功能上相当的方法,该方法也称为Eval,但是来自另一个类——DataBinder。

       é‡è¦æç¤ºï¼š

       é€šè¿‡Eval方法(尽管它来自DataBinder或Pageç±»),可以访问所绑定的数据项上的公共属性。让我澄清一下公共属性在该上下文中指什么,以及为什么我坚持把它们叫做属性。任何一个实现了IEnumerable接口的类都可以绑定到一个控件。实际的类列表当然包括DataTable(其中一个数据项在逻辑上对应于表记录),但是它还包括定制集合(其中一个数据项对应于给定类的一个实例。)Eval方法最终会查询该数据项对象以得到它的属性集。表示一个表记录的对象将返回它的列描述符;其他对象将返回它们的公共属性集。

       DataBinder类支持数据绑定表达式的生成和解析。它的静态重载方法Eval特别重要。该方法使用反射机制来解析和计算一个运行时对象的表达式。Eval方法的客户包括RAD工具,诸如Microsoft

       Visual

       Studio

       .NET设计器和Web控件,它们以声明的方式调用该方法用动态改变的值填充这些属性。

       1.

       Eval方法

       DataBinder.Eval方法的语法如下:

       <%#

       DataBinder.Eval(Container.DataItem,

       expression)

       %>

       ä¸Šè¿°ä»£ç ç‰‡æ–­ä¸­çœç•¥äº†ç¬¬3个可选参数。该参数是一个字符串,包含所绑定值的格式选择。Container.DataItem表达式引用对该表达式进行计算的对象。该表达式通常是一个字符串,表示数据项对象上要访问的字段的名称。它可以是一个包括索引和属性名的表达式。DataItem属性表示当前容器上下文中的对象。容器通常即将生成的该数据项对象(例如,DataGridItem对象)的当前实例。

       å‰é¢æ‰€ç¤ºçš„代码通常重复出现,而且以相同的形式。只有表达式和格式字符串在页与页之间会有所变化。

       2.

       æ›´ç®€æ´çš„Eval

       DataBinder.Eval的原始语法在ASP.NET

       2.0中可以被简化,这一点我们在前面的Repeater示例中已经看到。在ASP.NET

       2.0中,只要在ASP.NET

       1.x中接受如下表达式的地方:

       <%#

       DataBinder.Eval(Container.DataItem,

       expression)

       %>

       å°±å¯ä»¥ä½¿ç”¨ï¼š

       <%#

       Eval(expression)

       %>

       ä¸ç”¨è¯´ï¼ŒASP.NET

       2.0也是完全支持DataBinder对象的。

       åœ¨<%#

       ...

       %>界定符内出现的任何代码,都会得到ASP.NET运行库的特殊处理。让我们简单分析一下该代码会发生什么。编译该页面时,Eval调用作为一个独立的调用插入该页面的源代码中。如下代码说明了会发生什么:

       object

       o

       =

       Eval("lastname");

       string

       result

       =

       Convert.ToString(o);

       è¯¥è°ƒç”¨çš„结果被转换为一个字符串,并付给一个数据绑定的文字控件——DataBoundLiteralControl类的一个实例。然而把数据绑定的文字插入该页的控件树中。

       åœ¨ASP.NET

       2.0中,TemplateControlç±»(Page的父类)实际上新增了一个名为Eval的受保护的(但不是虚拟的)方法。如下伪代码说明该方法的工作机制:

       protected

       object

       Eval(string

       expression)

       {

       if

       (Page

       ==

       null)

       throw

       new

       InvalidOperationException(…);

       return

       DataBinder.Eval(Page.GetDataItem(),

       expression);

       }

       æ­£å¦‚我们可以看到的,Eval是建立在DataBinder.Eval方法之上的一个简单包装。DataBinder.Eval方法使用当前容器的数据项调用。非常明显,当前容器的数据在数据绑定操作之外为null——即,在调用DataBind之后的调用栈中。这一事实引起了Eval和DataBinder.Eval之间的一个关键区别。

       é‡è¦æç¤ºï¼š

       TemplateControl的Eval是一个数据绑定方法,在一个数据绑定操作中只能在一个数据绑定控件的上下文中使用。相反,DataBinder.Eval是一个完全成熟的方法,可以在程序中的任何地方使用。我们通常在定制的数据绑定控件的实现中使用它。我将在本书的姐妹篇《Programming

       Microsoft

       ASP.NET

       2.0

       Applications:

       Advanced

       Topics

       ã€‹ä¸­ä»‹ç»å®ƒã€‚

       3.

       èŽ·å¾—默认的数据项

       å‰é¢ç»™å‡ºçš„说明页面的Eval方法的行为的伪码,展示了Page类的GetDataItem方法。它是什么?如前所述,这一简化语法采用一个默认的Container.DataItem上下文对象。GetDataItem只不过是返回该对象的函数。

       æ›´ç²¾ç¡®åœ°è®²ï¼ŒGetDataItem是跟踪页面的当前绑定上下文的基于栈的机制的终点。该控件树中的每个控件在调用各DataBind方法时压入该栈中。DataBind方法返回时,控件从该栈中弹出。如果栈是空的,并且企图以编程的方式调用Eval方法,则GetDataItem抛出一个无效的操作异常。总之,我们只能在模板中使用Eval简化操作;如果需要在代码中的任何其他地方访问一个数据项的属性,则利用DataBinder.Eval方法,并显式地指出数据项对象。

       æç¤º

       å¦‚前所述,通常只有在定制的数据绑定控件的代码中才需要直接调用DataBinder.Eval方法。(我在Programming

       Microsoft

       ASP.NET

       2.0

       Applications:

       Advanced

       Topics中介绍了定制控件。)然而,如果发生这种情况,可能需要通过调用DataBinder.GetPropertyValue方法来保存几个内部调用和CPU周期。最终,这完全是由DataBinder.Eval完成的。

七爪源码:C# 中的扩展方法

       扩展方法在C#中允许将方法“添加”到现有类型,无需创建新的派生类型或修改原始类型。扩展方法实质上是静态方法,但其调用方式如同实例方法,这在C#、F#和Visual Basic的客户端代码中没有明显区别。常见的扩展方法包括向System.Collections.IEnumerable和System.Collections.Generic.IEnumerable添加查询功能的LINQ标准查询运算符。

       例如,使用System.Linq指令将标准查询运算符引入范围后,可以对整数数组调用OrderBy方法进行排序。扩展方法定义为静态方法,使用实例方法语法调用,第一个参数指定方法操作的类型,并带有this修饰符。扩展方法的范围取决于是否使用using指令显式导入命名空间。

       以下示例展示了为System.String类定义的扩展方法,WordCount方法,定义在非嵌套、非泛型的静态类中。使用using指令即可进入范围并调用该方法。调用扩展方法时使用实例方法语法,编译器将生成中间语言(IL)以对静态方法进行调用。

       扩展方法允许在代码中调用,MyExtensions类和WordCount方法都是静态的,可以通过其他静态成员访问。WordCount方法可以像其他静态方法一样被调用。

       扩展方法的调用在编译时进行。当编译器遇到方法调用时,首先在类型的实例方法中查找匹配项,如果没有找到,则搜索该类型定义的任何扩展方法,并绑定到第一个找到的扩展方法。如果一个类型有一个名为Process(int i)的方法,并且有一个具有相同签名的扩展方法,则编译器将始终绑定到实例方法。

       使用扩展方法的常见模式包括:

       1. 收集功能:过去,为给定类型创建实现System.Collections.Generic.IEnumerable接口并包含该类型集合功能的“集合类”是常见的做法。然而,通过使用System.Collections.Generic.IEnumerable上的扩展,可以实现相同功能,提供从任何集合调用功能的灵活性,如System.Array或System.Collections.Generic.List上的实现。

       2. 特定层的功能:在使用洋葱架构或其他分层应用程序设计时,域实体或数据传输对象通常不包含功能或仅包含适用于所有层的最小功能。扩展方法可用于为每个应用程序层添加特定功能,无需引入其他层不需要或不需要的方法。

C#-Linq源码解析之DefaultIfEmpty

       在Dotnet开发过程中,`DefaultIfEmpty`作为Enumerable的扩展方法,广为使用。本文简要解析该方法的关键源码,旨在帮助大家更好地掌握并运用此方法。

       `DefaultIfEmpty`用于返回一个`IEnumerable`,如果输入序列为空,则返回一个仅包含默认值的单例集合。

       比如有一个空集合,通过`DefaultIfEmpty`方法,我们可以向其添加一个默认元素。

       方法的核心在于使用延迟执行实现。Enumerable是延迟加载的,每次访问时才取值,因此在返回数据时需要使用`yield`。

       实现过程需利用`GetEnumerator()`来判断序列是否有元素。

       `DefaultIfEmpty`源码体现了其高效性与灵活性,可处理空集合,避免错误显示。

       使用`DefaultIfEmpty`可使代码更加优雅,简化逻辑处理。

       若发现更好的使用技巧,欢迎交流分享。本文旨在提供基础理解,希望对大家有所帮助。

       技术交流群:联系管理员微信加入(备注:进群);管理员微信:mm;关注公众号:DotNet编程大全

谁给简单介绍一下C#?

       C#(读做 "C sharp",中文译音“夏普”)是微软公司发布的一种面向对象的、运行于.NET Framework之上的高级程序设计语言,并定于在微软职业开发者论坛(PDC)上登台亮相.C#是微软公司研究员Anders Hejlsberg的最新成果.C#看起来与Java有着惊人的相似;它包括了诸如单一继承,界面,与Java几乎同样的语法,和编译成中间代码再运行的过程.但是C#与Java有着明显的不同,它借鉴了Delphi的一个特点,与COM(组件对象模型)是直接集成的,而且它是微软公司.NET windows网络框架的主角.

        在本文中,我将考察创建一种新计算机语言的一般动机,并将特别指明是什么原因导致了C#的出现.然后我将介绍C#和它与Java,c,c++的相似之处.其次我将讨论一些存在于Java和C#之间的高层次的,和基础的差别.我将以衡量在用多种语言开发大型应用程序的时候所需的知识(或者对这种知识的缺乏程度)来结束本文,而这正是.NET和C#的一个主要战略.目前,C#和.NET还只能以C#语言规则,以及Windows 的一个"d预览版本",还有MSDN上迅速增多的文档集子的形式获得(还没有最终定型).

        微软c#语言定义主要是从C和C++继承而来的,而且语言中的许多元素也反映了这一点.C#在设计者从C++继承的可选选项方面比Java要广泛一些(比如说structs),它还增加了自己新的特点(比方说源代码版本定义).但它还太不成熟,不可能挤垮Java.C#还需要进化成一种开发者能够接受和采用的语言.而微软当前为它的这种新语言大造声势也是值得注意的.目前大家的反应是:"这是对Java的反击."

        C#更象Java一些,虽然微软在这个问题上保持沉默.这也是意料中的事情,我觉得,因为Java近来很成功而使用Java的公司都报告说它们在生产效率上比C++获得了提高.

        Java所带来的巨大影响和大家对它的广泛接受已经由工作于这种语言和平台之上的程序员数量明显的说明了(估计世界范围内共有两百五十万程序员使用Java).由这种语言写成的应用程序的数量是令人惊讶的并已经渗透了每一个级别的计算,包括无线计算和移动电话(比如日本发明的Java电话).C#能够在用户领域获得这样的礼遇吗?我们必须等待并观望,就象已经由SSI公司的CEO和主席Kalpathi S. Suresh指出来的那样,"我发现所有这些都是渐进的.如果C#不存在,我们总能回到Java或C和C++.这些都不完全是新技术;它们在更大的意义上来说只是大公司制造的市场噱头.我们必须给他们时间安顿下来看看这些是不是真的对IT工业有什么影响."

       C#从Java继承而来的特点

       ç±»:在C#中类的申明与Java很相似.这是合理的因为经验告诉我们Java模型工作得很好.Java的关键字import已经被替换成using,它起到了同样的作用.一个类开始执行的起点是静态方法Main().下面的Hello World程序展示了基本的形式:

       using System;

       class Hello

       {

        static void Main()

        {

        Console.WriteLine("Hello, world");

        }

       }

        在这个例子中,System这个名字指向一个包括了基本C#实用类集合的命名空间(namespace).这个命名空间包括了Consoleç±»,它在这个例子中被用来输出一个字符串.类可以是抽象的和不可继承的:一个被申明成abstract的类不能被实例化;它只能被用做一个基类.C#关键字sealed就象Java关键字final,它申明一个类不是抽象的,但是它也不能被用做另一个类的基类.界面:就象在Java中一样,一个界面是一组方法集合的抽象定义.当一个类或结构体实现一个界面的时候,它必须实现这个界面中定义的所有方法.一个单一的类可以实现几个界面.也许以后会出现一些微妙的差别,但是这个特点看起来与Java相比没有变化.布尔运算:条件表达式的结果是布尔数据类型,布尔数据类型是这种语言中独立的一种数据类型.从布尔类型到其他类型没有直接的转换过程.布尔常量true和false是C#中的关键字.错误处理:如Java中那样,通过抛出和捕捉异常对象来管理错误处理过程.内存管理:由底层.NET框架进行自动内存垃圾回收.

       C#从C和C++继承的特点

       ç¼–译:程序直接编译成标准的二进制可执行形式.但C#的源程序并不是被编译成二进制可执行形式,而是一中中间语言,类似于JAVA字节码。如果前面的Hello World程序被保存成一个文本文件并被命名为Hello.cs,它将被编译成命名Hello.exe的可执行程序.

       ç»“构体:一个C#的结构体与C++的结构体是相似的,因为它能够包含数据声明和方法.但是,不象C++,C#结构体与类是不同的而且不支持继承.但是,与Java相同的是,一个结构体可以实现界面.

       é¢„编译:C#中存在预编译指令支持条件编译,警告,错误报告和编译行控制.可用的预编译指令有:

       #define

       #undef

       #if

       #elif

       #else

       #endif

       #warning

       #error

       #line []

       æ²¡æœ‰äº†#include 伪指令.你无法再用#define 语句对符号赋值,所以就不存在源代码替换的概念--这些符号只能用在#if和#elif伪指令里.在#line伪指令里的数字(和可选的名字)能够修改行号还有#warning和#error输出结果的文件名.

       æ“ä½œç¬¦é‡è½½:一些操作符能够被重载,而另一些则不能.特别的是,没有一个赋值运算符能够被重载.能够被被重载的单目操作符是:

       + - ! ~ ++ -- true false

       èƒ½å¤Ÿè¢«é‡è½½çš„二元运算符是:

       + - * / % & | ^ << >> == != > < >= <=

       C#独有的特点

        C#最引人入胜的地方是它和Java的不同,而不是相似的地方.这一节(和这个系列第二部分的大部分地方)讲述了C#实现的和Java不同的地方或者Java根本没有的特点.

       ä¸­é—´ä»£ç :微软在用户选择何时MSIL应该编译成机器码的时候是留了很大的余地.微软公司很小心的声称MSIL不是解释性的,而是被编译成了机器码.它也明白许多--如果不是大多数的话--程序员认为Java程序要不可避免的比C编写的任何东西都要慢.而这种实现方式决定了基于MSIL的程序(指的是用C#,Visual Basic,"Managed C++"--C++的一个符合CLS的版本--等语言编写的程序)将在性能上超过"解释性的"Java代码.当然,这一点还需要得到事实证明,因为C#和其他生成MSIL的编译器还没有发布.但是Java JIT编译器的普遍存在使得Java和C#在性能上相对相同.象"C#是编译语言而Java是解释性的,"之类的声明只是商业技巧.Java的中间代码和MSIL都是中间的汇编形式的语言,它们在运行时或其它的时候被编译成机器代码.

       å‘½åç©ºé—´ä¸­çš„申明:当你创建一个程序的时候,你在一个命名空间里创建了一个或多个类.同在这个命名空间里(在类的外面)你还有可能声明界面,枚举类型和结构体.必须使用using关键字来引用其他命名空间的内容.

       åŸºæœ¬çš„数据类型:C#拥有比C,C++或者Java更广泛的数据类型.这些类型是bool, byte, ubyte, short, ushort, int, uint, long, ulong, float, double,和decimal.象Java一样,所有这些类型都有一个固定的大小.又象C和C++一样,每个数据类型都有有符号和无符号两种类型.与Java相同的是,一个字符变量包含的是一个位的Unicode字符.C#新的数据类型是decimal数据类型,对于货币数据,它能存放位进制数字.

       ä¸¤ä¸ªåŸºæœ¬ç±»:一个名叫object的类是所有其他类的基类.而一个名叫string的类也象object一样是这个语言的一部分.作为语言的一部分存在意味着编译器有可能使用它--无论何时你在程序中写入一句带引号的字符串,编译器会创建一个string对象来保存它.

       å‚数传递:方法可以被声明接受可变数目的参数.缺省的参数传递方法是对基本数据类型进行值传递.ref关键字可以用来强迫一个变量通过引用传递,这使得一个变量可以接受一个返回值.out关键字也能声明引用传递过程,与ref不同的地方是,它指明这个参数并不需要初始值.

       ä¸ŽCOM的集成:C#对Windows程序最大的卖点可能就是它与COM的无缝集成了,COM就是微软的Win组件技术.实际上,最终有可能在任何.NET语言里编写COM客户和服务器端.C#编写的类可以子类化一个以存在的COM组件;生成的类也能被作为一个COM组件使用,然后又能使用,比方说,JScript语言子类化它从而得到第三个COM组件.这种现象的结果是导致了一个运行环境的产生,在这个环境里的组件是网络服务,可用用任何.NET语言子类化.

       ç´¢å¼•ä¸‹æ ‡:一个索引与属性除了不使用属性名来引用类成员而是用一个方括号中的数字来匿名引用(就象用数组下标一样)以外是相似的.

       public class ListBox: Control

       {

        private string[] items;

        public string this[int index]

        {

        get

        {

        return items[index];

        }

        set

        {

        items[index] = value;

        Repaint();

        }

        }

       }

       å¯ä»¥ç”¨ä¸€ä¸ªå¾ªçŽ¯å™¨æ¥åŒ¿åå¼•ç”¨å­—符串内部数组成员,就象下面这样:

       ListBox listBox = ...;

       listBox[0] = "hello";

       Console.WriteLine(listBox[0]);

       ä»£ç†å’Œåé¦ˆ:一个代理对象包括了访问一个特定对象的特定方法所需的信息.只要把它当成一个聪明的方法指针就行了.代理对象可以被移动到另一个地方,然后可以通过访问它来对已存在的方法进行类型安全的调用.一个反馈方法是代理的特例.event关键字用在将在事件发生的时候被当成代理调用的方法声明.

       è¡¥å……:

       C#简史——摘自《程序员》杂志-月刊

       C# 简史

       ç¼–者按:时间过得真快,居然现在就可以写C#的简史了。但是想想也不奇怪,C#可谓

       èµ·ç‚¹é«˜ã€å‘展快的新一代语言,它的这五年走过了很多前辈十几年的路。公允地说,C#是目

       å‰å…¼é¡¾ç³»ç»Ÿå¼€å‘和应用开发的最佳实用语言,并且很有可能成为编程语言历史上的第一个“全

       èƒ½â€åž‹è¯­è¨€ã€‚看过这篇简史,我们都应该明白,不要再把C#看成年轻后生了——只要是“马

       æ‹‰å¤šçº³â€ï¼Œå°±æ—©æ™šå½““球王”。

       C# 1.0,纯粹的面向对象

       å½“时间回溯到年底,微软正在忙于新一代COM的设计工作。此前,COM一直是组件化开发中非常成功的一种技术;但由于它仅提供了二进制

       å±‚面上的统一,因此无法将类型信息和用于支持基础平台和开发工具的信息放到组件中。这时,Java正在逐步走向成熟。于是,微软学习Java

       çš„做法,将虚拟机的概念引入到了COM领域;同时,微软提出了“元数据”的概念,用于描述组件的类型信息和工具支持信息,并决定将其放入

       åˆ°ç»„件当中。这种“COM虚拟机”的名字在经历了若干争论后,最终被定为CLR(Common Language Runtime,公共语言运行时)。与此同时,微

       è½¯æå‡ºäº†åœ¨è¯¥è¿è¡Œæ—¶ä¸Šè¿ä½œçš„语言应该遵循的一些规则,以及该虚拟机的类型系统和指令集——所有这些规范形成了最终的C L I(Common

       Language Infrastructure,公共语言基础设施),并提交给了ECMA委员会。同时,微软开发了CLI的一个实现,这就是大名鼎鼎的.NET了。

       å¹´æœˆï¼Œå¾®è½¯å¯åŠ¨äº†ä¸€ä¸ªå…¨æ–°çš„语言项目——COOL,这是一款专门为CLR设计的纯面向对象的语言,也正是本文的主角——C#的前身。历时

       åŠå¹´æœ‰ä½™ï¼Œå¹´7月份,微软完成了COOL语言的一个内部版本。直到年2月份,微软才正式将COOL语言更名为C#。据说起这个名字是因为

       C#开发小组的人很讨厌搜索引擎,因此把大部分搜索引擎无法识别的“#” 字符作为该语言名字的一部分;还有一种说法是在音乐当中“#”是

       å‡è°ƒè®°å·ï¼Œè¡¨è¾¾äº†å¾®è½¯å¸Œæœ›å®ƒåœ¨C的基础上更上一层楼的美好愿望——当然这些都只是传说,无从考证。又是历经了一系列的修改,微软终于在

       å¹´7月发布了C#语言的第一个预览版。因此人们一般认为C#是年发布的,并以此来计算它的“年龄”。在此后的一年多时间里,微软一

       ç›´åœ¨ä¿®è¡¥å„个测试版本中的BUG。直到年2月,微软终于推出了迟迟未上市的Visual Studio 7.0,并将其定名为“VisualStudio .NET

       â€ã€‚随着这套开发环境的出炉,开发者们终于看到了C#语言的第一个正式版本——C# 1.0。此后,微软马不停蹄,Visual Studio也恢复了往日

       çš„开发进度。在年5月,微软如期推出了Visual Studio .NET ,同时也发布了C#的改进版本——C# 1.1。这一时期的C#(以下称为C#

       1.x)提出了纯粹的面向对象概念,并在语言特性中展现得淋漓尽致。C++并非纯面向对象的,为了和C兼容以及提供更高的执行效率,它保留了

       å¾ˆå¤šæ¨¡å—化的东西。Java尽管号称是面向对象的,但实际上,对于对象所应该具备的三种构成结构——属性、方法和事件,Java仅提供了方法

       ï¼Œå…¶å®ƒä¸¤ç§ç»“构都要通过方法来模拟。在C# 1.x中,所有面向对象的概念都在语言中得到了非常好的体现。同时,C#还通过类类型、值类型和

       æŽ¥å£ç±»åž‹çš„概念形成了统一的类型系统。C#使用了大家所熟知的语法实现了方法,以至于很多人认为C#和Java、C++等面向对象语言“非常相像

       â€ï¼Œè¿™ä½¿å¾—从使用其他面向对象语言转到使用C#的过程非常简单。此外,C#还通过无参数列表的方法声名语法,结合get/set访问器实现了优雅

       çš„属性语法。其中的get访问器相当于获取属性值的方法,可以通过一些运算返回最终的结果,而不是简单地返回一个变量的值;而set访问器

       ç›¸å½“于设置属性值的方法,在其中可以进行一系列检测,最后将属性值赋给相应的变量。同时,通过同时提供get和set访问器、只提供get访问

       å™¨å’Œåªæä¾›set访问器,还可以很方便地实现可读写、只读和只写的属性。C#的这种属性语法,使得一个属性在提供该属性的类的内部看来,非

       å¸¸åƒä¸€ç»„方法;而对于外部调用类看来,访问一个对象的属性和访问它的公共域没有任何区别。

       é€šè¿‡å§”托(稍后介绍),结合关键字event,C#提供了优雅的事件概念。使用+=运算符,开发者可以非常方便地将一个事件处理器关联到一个事

       ä»¶ä¸Šï¼Œè¿™ä¸ªè¿‡ç¨‹ç§°ä¹‹ä¸ºâ€œè®¢é˜…”一个事件。由于委托内部封装了一个调用链表,因此可以方便地为一个事件添加多个事件处理器,这些处理器

       ä¼šè‡ªåŠ¨åœ°ä¾æ¬¡è°ƒç”¨ã€‚多年的开发语言进化证明,函数指针是非常重要也是非常危险的语言特征之一。同时,基于函数指针的回调机制也Windows

       æ ¸å¿ƒæ¦‚念之一。然而,由于函数指针很难验证参数的类型准确性,因此C#(确切地说是CLI)提出了“委托”的概念,这是一种类型安全的函数

       æŒ‡é’ˆé“¾è¡¨ã€‚这意味着,C#不仅可以提供回调机制,同时调用回调的一方还无需在其内部维护函数指针列表,所要做的仅仅是声名一个具有恰当

       å§”托类型的公共成员即可;而提供回调的一方也只需通过构造一个带有指定方法的相应委托实例,并通过“+=”运算符添加到回调列表即可。

       å°½ç®¡C# 1.x提供了如此多的新鲜概念,但实际上,这些概念都是由CLI提出的。因此当将一个C#源程序编译为可执行文件时,编译器做的工作相

       å¯¹è€Œè¨€å¹¶ä¸å¤šã€‚需要编译器代劳的是要将一个简单的委托定义语句翻译为一个继承自System.MulticastDelegate类型定义。

       C# 2.0,泛型编程新概念

       å¾®è½¯æœ¬æ‰“算继续保证开发进度,并在年推出Visual Studio .NET ,但由于其间软件工程学尤其是软件管理学的大规模进步,微软所提

       ä¾›çš„这种仅具备开发和调试功能的IDE已经无法满足团队开发的需求。因此微软决定在项目设计和管理工具方面进行了进一步研发,并将其集成

       åˆ°Visual Studio中,以赢回原有的市场。因此,微软将Visual Studio.NET “改名”为Visual Studio ,并决定推迟一年发布。不过

       ï¼Œå¾®è½¯è¿˜æ˜¯åšæŒåœ¨å¹´çš„6月份发布了Visual Studio的第一个Beta 版,同时向开发者展示了C#语言的2.0版本。年4月,微软发布了

       Visual Studio Beta2,这已经是具备了几乎全部功能的VisualStudio,包括的产品有SQL Server、Team Foundation Server和

       TeamSuite。这时的C#编译器已经能够处理C# 2.0中所有的新特性。C# 2.0为开发者带来的最主要的特性就是泛型编程能力。和面向对象思想一

       æ ·ï¼Œæ³›åž‹æ€æƒ³ä¹Ÿæ˜¯ä¸€ç§å·²ç»æˆç†Ÿçš„编程思想,但依然是没有哪一种主流开发语言能够支持完备的泛型概念。这主要是因为泛型的概念在一定程

       åº¦ä¸Šå¯¹é¢å‘对象概念进行冲击,同时,由于在编译期间对类型参数的完全检测很难做到,很多问题会被遗留到运行时。C# 2.0别出心裁,对泛

       åž‹ç±»åž‹å‚数提出了“约束”的新概念,并以优雅的语法体现在语言之中。有了约束,结合编译器强大的类型推断能力,可以在编译时

       å‘现几乎所有“危险”的泛型应用。C# 2.0的另一个突出的特性就是匿名方法,用来取代一些短小的并且仅出现一次的委托,使得语言结构更

       åŠ ç´§å‡‘。匿名方法除了可以使得事件处理器的编写更加精简以外,还将开发者带入了程序设计的一个新的领域——函数式编程,曾经有高人就

       ç”¨åŒ¿åæ–¹æ³•ç»“合泛型编程实现了函数式编程中的重要结构—— Lambda 表达式。尽管这种实现显得很繁琐而且不易理解,但毕竟是实现了。最

       ç»ˆï¼Œå‡½æ•°å¼ç¼–程还是被引入到了C#语言中,这将在下一节中为大家讲述。

       æ­¤å¤–,C# 2.0还进一步增强了语言的表达能力。在C# 2.0中,属性语法中的get和set访问器可以拥有不同的权限,这就使得定义一个在库的内

       éƒ¨å¯è¯»å†™ï¼Œè€Œåœ¨åº“的外部只读的属性成为可能。同时,C# 2.0还提供了迭代器的概念,这使得一个类无需实现IEnumerator 和IEnumerable接口

       å³å¯å®žçŽ°ä¸€ä¸ªå¯ä»¥è¿›è¡ŒéåŽ†çš„类型,并且无需在类型中维护迭代状态。此时的.NET已经得到了很广泛的认可,并且因为元数据为组件带来了强

       å¤§çš„自我描述能力,许多程序库厂商被吸引到.NET平台上来。随着.NET程序库数量的增长,逐渐暴露了命名的问题。在面向对象技术广泛发展

       åŽï¼Œäººä»¬å°±æ„è¯†åˆ°åå­—的管理问题,因此几乎所有的面向对象语言都提出了“命名空间”的概念;

       è€Œåœ¨C# 1.x时代,这个问题再一次出现。如果一个库厂商XX 希望以XX.System来命名他们自己的系统基础库,那么当开发者使用using System

       è¯­å¥æ—¶å°±ä¼šäº§ç”Ÿæ­§ä¹‰ã€‚为此。C# 2.0中提供了global关键字,这为.NET库中所有的命名空间提供了一个“根”,通过指定global::System和

       global::XX.System就可以区别两个库了。这一时期的C#编译器变得非常复杂,泛型的引入使得编译器不得不具备超强的类型推断能力。同时,

       è¿­ä»£å™¨çš„思想并非是在CLI层面上实现的,而是由编译器自动生成了实现I E n u m e r a t o r 和IEnumerable接口类型。

       C# 3.0,魔鬼

       åœ¨ç»åŽ†äº†ä¸€ç³»åˆ—的改进和完善后,微软决定于年月发布Visual Studio,该开发环境将正式支持C#2.0。由于此前推出了数个预览版

       å’Œæµ‹è¯•ç‰ˆï¼Œå¤§å®¶çš„期待之情似乎已经不是那么强烈了。而年9 月份的PDC大会则为开发者们带来了另外的惊喜——C#3.0(研发代号“Orcas

       â€â€”—魔鬼)的技术预览版。

       è¯´åˆ°C# 3.0,就不得不提一下微软的LINQ 项目,LINQ(语言集成查询,Language Integrated Query)提出了一种通过面向对象语法来实现对

       éžé¢å‘对象数据源的查询技术,可查询的数据源从关系型数据库延伸到一般意义上的集合(如数组和列表)以及XML。而C# 3.0则是率先实现了

       LINQ的语言。在C# 3.0中,我们可以用类似于SQL语句的语法从一个数据源中轻松地得到满足一定条件的对象集合。例如要查找一个字符串

       æ•°ç»„names中所有长度大于5的字符串,就可以写: var longname = from n in names wheren.Length > 5 select n;这样我们就得到一个

       æ–°çš„字符数组longname,其中包含了我们所需要的结果。这种语句称作查询语句,与SQL语句唯一的区别是C#中的查询语句往往把select子句放

       åˆ°æœ€åŽï¼ˆè¿™åè€Œå€’有些类似于中文的阅读顺序了)。初次看到这样一个语句,我们可能会有很大疑问:这还是C#语言吗?这的确是合乎语法规

       åˆ™çš„C#代码,而且编译器可以识别这种语法。然而实际上,C#编译器并不会对这种语法进行实际的的编译,而是将其翻译为正常的方法调用:

        var longname = names.Where(n => n.

       Length > 5).Select(n);然后再进行进一步的编译。在上面的例子中已经说明,names是一个存放有字符串的数组,而数组类型并没有Where的

       æ–¹æ³•ã€‚的确,Where并非names的成员方法,微软也没有对数组类型进行任何改动。这是C# 3.0中另外一个重要的新特性:扩展方法。扩展方法

       æ˜¯å®šä¹‰åœ¨å…¶ä»–静态类中的静态方法,其第一个参数的类型就是希望扩展的类型,并且这个参数被冠以this修饰符。扩展方法是静态的,但可以

       åƒè°ƒç”¨è¢«æ‰©å±•ç±»åž‹çš„实例方法那样进行调用,看起来好像是被扩展类型自己的方法一样。这就为语言带来了很大的灵活性,我们可以将一组近

       ä¼¼çš„功能如上面的Where 和Select等(这在LINQ中被称作“标准查询表达式”)定义在一个外部类中,这样既无须修改现有类型,又可以将新

       åŠŸèƒ½ç»„织在一起。当然,为了做到面向对象的封装性,扩展方法只能在被扩展类型的公共成员上进行操作,如果需要从内部对类型进行改进,

       å°±å¿…须改变现有类型的代码。在Where方法的参数列表里,我们又发现了一种奇怪的语法:n => n.Length > 5。这就是我们上文提到过的

       Lambda 表达式。微软的官方规范中称,Lambda 表达式是匿名方法的一种自然进化。因此Lambda 表达式其实也是一种特殊的委托,由编译器负

       è´£ç”Ÿæˆä¸€ä¸ªåŒ¿åçš„委托类型,它接受一个字符串类型的参数n;返回值为布尔类型,表示n的长度是否大于5;其中的参数类型和返回值类型都是

       ç”±ç¼–译器推断而来的。说到类型推断,还要解释的一点就是上面的语句中出现的新关键字var。从出现的位置来看,var应该是一个类型。然而

       è¿™åˆä¸æ˜¯ä¸€ä¸ªC#内建类型,也不是CLI提出的新类型;它只是一个“占位符”,它的确表示一个类型,但具体是什么类型需要编译器在编译期间

       è¿›è¡ŒæŽ¨æ–­ã€‚Lamda表达式的真正意义不仅仅在于简化了委托的编写方式,更重要的是它把代码表达式体现为了数据。换句话说,Lambda表达式不

       ä»…可以被编译为一段可以执行的代码(类似于匿名方法),也可以将其翻译为一个数据结构——表达式树。而如何处理Lambda 表达式,是由编

       è¯‘器根据Lambda表达式的使用方式来自动确定的。当把一个Lambda表达式赋给一个具有委托类型的域、属性或变量时,编译器像编译匿名方法

       ä¸€æ ·å°†è¡¨è¾¾å¼ä½“翻译成一段可执行代码;而当把一个L a m b d a 表达式赋给一个具有Expression<T>类型的域、属性或变量时,编译器就会将

       Lambda表达式解析为一个表达式树。对于翻译为代码的Lambda,可以向调用委托那样进行调用,而对于翻译为表达式树的Lambda表达式,就不

       å¯ä»¥äº†ï¼Œä¼šå¾—到一个编译错误。但表达式树存在于一个由编译器生成的数据结构中,因此可以在运行时对其进行分析甚至修改。

       é™¤äº†ä¸Šé¢æåˆ°çš„一些重大改进之外,C# 3.0也对细微的语法进行了一些改进,使C#语言变得更加优雅和全面。值得说明的是,C# 3.0经过编译

       åŽç”Ÿæˆçš„IL代码,完全是基于.NET 2.0的,C#语言已经远远跑在了他所栖生的平台前面。这一时期的C#语言离CLI已经越来越远了,编译器的工

       ä½œä¹Ÿæ„ˆåŠ ç¹é‡èµ·æ¥ã€‚首先很多语言结构(如查询表达式和Lambda 表达式)都不是CLI中提供的特性,因此需要编译器进行大量的转译工作;其

       æ¬¡æ˜¯è¿™äº›è¯­è¨€ç»“构带来的大量类型推断任务,也都是靠编译器来完成的。

       C#走到了3.0以后,已经完全不再是当年那个“简单”的语言了。它的开发者称其为“魔鬼”,而琳琅满目的新特性也的确让开发者们眼花缭乱

       ï¼Œç”šè‡³æ„Ÿåˆ°ææƒ§ã€‚语言集成查询的引入,使得前一段时期内为开发者们广泛讨论的ORM概念得到了更加深入地体现,尤其是它所支持的数据源之

       å¹¿æ³›ï¼Œè®©ORM理念变得已经不再必要了;而一些“.NET中的ORM实现”,似乎也成了完全不必要的扩展项目了。Lambda 表达式的引入,使得C#

       å°†å¯ä»¥è½»æ¾åœ°å®Œæˆç‰¹å®šé¢†åŸŸï¼ˆDomain-Specific)的开发。一个成功的开发人员在面对新鲜事物和新的困难时,兴奋是远大于恐惧的。

       è®©é­”鬼来得更猛烈些吧!

copyright © 2016 powered by 皮皮网   sitemap