0

0

C# 2.0 Specification(二)

黄舟

黄舟

发布时间:2017-01-03 10:14:43

|

1096人浏览过

|

来源于php中文网

原创

19.1.5泛型方法

在某些情形下,类型参数对于整个类不是必需的,而只对特定方法内是必需的。经常,当创建一个接受泛型类型作为参数的方法时就是这样。例如,当使用早先描述的stack类时,

一个通用的模式可能是在一行中压入多个值,在一个单一的调用中写一个方法这么做也是很方便的。对于特定的构造类型,例如Stack,这个方法看起来像这样。

void PushMultiple(Stack stack ,params int[] values)
{
foreach(int value in values) 
stack.Push(value);
}

这个方法可以用于压入多个int值到一个Stack中。

Stack stack = new Stack();
PushMultiple(stack, 1,2, 3, 4);

然而,先前的方法只对于特定的构造类型Stack有效。要让它对于Stack也起作用,方法必须被作为泛型方法而编写。泛型方法在方法的名字后面在“”分界符之间

指定了一个或多个类型参数。类型参数可以在参数列表,返回类型和方法体之内被使用。一个泛型的PushMultiple方法将会是这样。

void PushMultiple(Stack<>T stack , params T[] values)
{
foreach(T value in values) stack.Push(value);
}

使用这个泛型方法,你可以压入多个项到任意Stack中。当调用一个泛型方法时,类型参数值在方法调用的尖括号中被给定。例如

Stack stack = new Stack();
PushMultiple(stack , 1,2,3,4);

这个泛型PushMultiple方法比先前的版本更具有重用性,因为它可以工作在任何Stack上,但似乎在调用的时候不太方便,因为必须提供T作为一个类型参数传递给方法。在许多情形下,编译器使用一种称为类型推断(type inferencing)处理,从传递给方法的其他参数推断正确的类型参数。在先前的例子中,因为第一个正式参数是Stack类型,而后续的参数是int 类型,因此编译器可以推断类型参数值必须是int。由此,在调用泛型PushMultiple方法时可以不指定类型参数。

Stack stack = new Stack();
PushMultiple(stack , 1,2, 3, 4);

19.2匿名方法

事件句柄和其他回调函数经常需要通过专门的委托调用,从来都不是直接调用。虽然如此,我们还只能将事件句柄和回调函数的代码,放在特定方法中,再显式为这个方法创建委托。相反,匿名方法(anonymous method)允许一个委托关联的代码被内联的写入使用委托的地方法,很方便的是这使得代码对于委托的实例很直接。除了这种便利之外,匿名方法还共享了对本地语句包含的函数成员的访问。为了使命名方法达成共享(区别于匿名方法),需要手工创建辅助类,并将本地成员“提升(lifting)”为类的域。



下面的例子展示了一个简单的输入表单,它包含一个列表框、一个文本框和一个按钮。当按钮被按下时,在文本框中一个包含文本的项就被添加到列表框。

class InputForm:Form
{
ListBox listBox;
TextBox textbox;
Button addButton;
pubic MyForm()
{
listBox = new ListBox(…);
textbox = new TextBox(…);
addButon = new Button(…);
addButton.Click += new EventHandler(AddClick);
}
void AddClick(object sender , EventArgs e)
{
listBox.Items.Add(textbox.Text);
} 
}

即使作为对按钮的Click事件的响应只有唯一的一条语句需要执行。那条语句也必须放在一个具有完整的参数列表的单独的方法中,并且还必须手工创建引用那个方法的EventHandler委托。使用匿名方法,事件处理代码将变得相当简洁。

class InputForm:Form
{
ListBox listBox;
TextBox textbox;
Button addButton;
pubic MyForm()
{
listBox = new ListBox(…);
textbox = new TextBox(…);
addButon = new Button(…);
addButton.Click +=delegate{
listBox.Items.Add(textBox.Text.);
}
}

匿名方法由关键词delegate和一个可选的参数列表,以及一个封闭在“{”和“}”分界符中的语句组成。先前的例子中匿名方法没有使用由委托所提供的参数,所以便省略了参数列表。如果要访问参数,匿名方法可以包含一个参数列表。

addButton.Click += delegate(object sender , EventArgs e){
MessageBox.Show(((Button)sender).Text);
};

在前面的例子中,将会发生一次从匿名方法到EventHandler委托类型(Click事件的类型)的隐式转换。这种隐式转换是可能的,因为参数列表和委托类型的返回值与匿名方法是兼容的。关于兼容性的确切规则如下:

如果下列之一成立,那么委托的参数列表与匿名方法是兼容的。

- 匿名方法没有参数列表,并且委托没有out 参数。
- 匿名方法包含的参数列表与委托的参数在数量、类型和修饰符上是精确匹配的。

如果下列之一成立,那么委托的返回类型与匿名方法兼容。

- 委托的返回类型是void,匿名方法没有返回语句,或者只有不带表达式的return 语句。
- 委托的返回类型不是void ,并且在匿名方法中,所有return 语句相关的表达式可以被隐式转换到委托的类型。

在委托类型的隐式转换发生以前,委托的参数列表和返回类型二者都必须与匿名方法兼容。

下面的例子使用匿名方法编写了“内联”函数。匿名方法被作为Function委托类型而传递。

using System;
delegate double Function(double x);
class Test
{
static double[] Apply(double[] a ,Function f)
{
double[] result = new double[a.Length];
for(int i=0;i

Apply方法适用一个 double[]元素的给定的Function,并返回一个double[]作为结果。在Main方法中,传递给Apply的第二个参数是一个匿名方法,它与Fucntion委托类型兼容。该匿名方法只是返回参数的平方,而Apply调用的结果是一个double[] ,在a中包含了值的平方。

MultiplyAllBy方法返回一个由一个给定factor(因数)的在参数数组a中的每个值相乘而创建的double[] 。要得到结果,MultiplyAllBy调用了Apply方法,并传给它一个匿名方法(在参数上乘以因数factor)。

如果一个本地变量或参数的作用域包括了匿名方法,则该变量和参数被称为匿名方法的外部变量(outer variable)。在MultiplyAllBy方法中,a和factor是传递给Apply的匿名方法的外部变量,因为匿名方法引用了factor,factor被匿名方法所捕获(capture)[/b]。通常,局部变量的生存期被限制在它所关联的块或语句的执行区。然而,被捕获的外部变量将一直存活到委托所引用的匿名方法可以被垃圾回收为止。

19.2.1方法组转换

如前面所描述的,匿名方法可以被隐式地转换到与之兼容的委托类型。对于一个方法组,C#2.0允许这种相同类型的转换,即在几乎任何情况下都不需要显式地实例化委托。例如,下面的语句

addButton.Click += new EventHandler(AddClick);
Apply(a , new Function(Math.Sin));

可以被如下语句代替.

95Shop仿醉品商城
95Shop仿醉品商城

95Shop可以免费下载使用,是一款仿醉品商城网店系统,内置SEO优化,具有模块丰富、管理简洁直观,操作易用等特点,系统功能完整,运行速度较快,采用ASP.NET(C#)技术开发,配合SQL Serve2000数据库存储数据,运行环境为微软ASP.NET 2.0。95Shop官方网站定期开发新功能和维护升级。可以放心使用! 安装运行方法 1、下载软件压缩包; 2、将下载的软件压缩包解压缩,得到we

下载
addButton.Click += AddClick;
Apply(a , Math.Sin);

当使用这种简短的形式时,编译器将自动推断哪一个委托类型需要实例化,但其最后的效果与较长的表达形式是一样的。

19.3迭代器

C#的foreach语句被用于迭代一个可枚举(enumerable)集合的所有元素。为了可以被枚举,集合必须具有一个无参数GetEnumerator方法,它返回一个enumertor(枚举器)。一般情况下,枚举器是很难实现的,但这个问题使用迭代器就大大地简化了。

迭代器是一个产生值的有序序列的语句块。迭代器不同于有一个或多个yield语句存在的常规语句块。

yield return语句产生迭代的下一个值。 
yield break语句指明迭代已经完成。

只要函数成员的返回类型是枚举器接口(enumerator interface)或可枚举接口(enumerable interface)之一,迭代器就可以被用作函数体。

枚举器接口是System.Collections.IEnumerator和由Sysetm.Collections.Generic.IEnumerator所构造的类型。 
可枚举接口是System.Collections.IEnumerable和由System.Collections.Generic.IEnumerable构造的类型。


迭代器不是一种成员,它只是实现一个函数成员的方式,理解这点是很重要的。一个通过迭代器被实现的成员,可以被其他可能或不可能通过迭代器而被实现的成员覆盖和重载。

下面的Stack类使用迭代器实现了它的GetEnumerator方法。这个迭代器依序枚举了堆栈从顶到底的所有元素。

using System.Collections.Generic;
public class Stack:IEnumerable
{
T[] items;
int count;
public void Push(T data){…}
public T Pop(){…}
public IEnumerator GetEnumerator()
{
for(int i =count-1;i>=0;--i){
yield return items[i];
}
}
}

GetEnumerator方法的存在使得Stack成为一个可枚举类型,它使得Stack的实例可被用在foreach语句中。下面的例子压入从0到9 的值到一个整数堆栈中,并且使用一个foreach循环依序显示从堆栈顶到底的所有值。

using System;
class Test
{
static void Main()
{
Stack stack = new Stack();
for(int i=0;i<10;i++) stack.Push(i);
foreach(int i in stack) Console.Write(“{0}”,i);
Console.WriteLine();
}
}

例子的输出入下:

9 8 7 6 5 4 3 2 1 0

foreach语句隐式地调用了集合的无参数GetEnumerator方法以获得一个枚举器。由集合所定义的只能有一个这样的无参数 GetEnumerator方法,但经常有多种枚举方式,以及通过参数控制枚举的方法。在这种情况下,集合可以使用迭代器实现返回可枚举接口之一的属性和方法。例如,Stack可能引入两个IEnumerable类型的新属性,TopToBottom和BottomToTop。

using System.Collections.Generic;
public class Stack: IEnumerable
{
T[] items;
int count;
public void Push(T data){…}
public T Pop()P{…}
public IEnumerator GetEnumerator()
{
for(int i= count-1;i>=0;--i)
{ 
yield return items[i];
}
}
public IEnumerable TopBottom{
get{
return this;
}
}
public IEnumerable BottomToTop{
get{
for(int I = 0;i

TopToBottom属性的get访问器只是返回this,因为堆栈自身是可枚举的。BottomToTop属性返回一个使用C#迭代器实现的枚举。下面的例子展示了,属性如何用于枚举堆栈元素。

using System;
class Test
{
static void Main()
{
Stack stack = new Stack();
for(int i = 0 ;i<10 ;i++) stack.Push(i);
for(int i in stack..TopToBottom) Console.Write(“{0}”,i);
Console.WriteLine();
for(int i in stack..BottomToTop) Console.Write(“{0}”,i);
Console.WriteLine();
} 
}

当然,这些属性同样也可以在foreach语句之外使用。下面的例子将调用属性的结果传递给了一个单独的Print方法。该例子也展示了一个用作FromToBy接受参数的方法体的迭代器。

using System;
using System.Collections.Generic;
class Test
{
static void Print(IEnumerable collection)
{
foreach(int i in collection) Console.Write(“{0}”,i);
Console.WriteLine();
}
static IEnumerable FromToBy(int from ,int to , int by)
{
for(int i =from ;i<=to ;i +=by)
{
yield return I;
}
}

static void Main()
{
Stack stack = new Stack();
for(int i= 0 ;i<10;i ++) stack.Push(i);
Print(stack.TopToBottom);
Print(stack.BottomToTop);
Print(FromToBy(10,20,2));
}
}

该例子的输出如下。

9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9
10 12 14 16 18 20

泛型和非泛型可枚举接口包含一个单一的成员,一个不接受参数的GetEnumerator方法 ,它一个枚举器接口。一个枚举充当一个枚举器工厂。每当调用了一个正确地实现了可枚举接口的类的GetEnumerator方法时,都会产生一个独立的枚举器。假定枚举的内部状态在两次调用GetEnumerator之间没有改变,返回的枚举器应该产生相同集合相同顺序的枚举值。在下面的例子中,这点应该保持,即使枚举的生存期发生交叠。

using System;
using System.Collections.Generic;
class Test
{
static IEnumerable FromTo(int from , int to)
{
while(from<=to) yield return from++;
}

static void Main()
{
IEnumerable e = FromTo(1,10);
foreach(int x in e)
{
foreach(int y in e)
{
Console.WriteLine(“{0,3}”,x*y);
}
Console.WriteLine();
}
}
}

先前的代码打印了整数1到10 的乘法表。注意,FromTo方法只被调用了一次用来产生枚举e。然而,e.GetEnumerator()被调用了多次(通过foreach语句),以产生多个等价的枚举器。这些枚举器都封装了在FromTo声明中指定的迭代器代码。注意迭代器代码修改了from参数。

不过,枚举器是独立地运作的,因为每个枚举器都给出 from 和to它自己的拷贝。枚举器之间过渡状态的共享是众多细微的瑕疵之一,当实现枚举和枚举器时应该避免。C#迭代器的设计可用于避免这些问题,从而以一种简单直观地方式实现健壮的枚举和枚举器。

以上就是C# 2.0 Specification(二)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

28

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

8

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

31

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

3

2026.01.26

windows安全中心怎么关闭 windows安全中心怎么执行操作
windows安全中心怎么关闭 windows安全中心怎么执行操作

关闭Windows安全中心(Windows Defender)可通过系统设置暂时关闭,或使用组策略/注册表永久关闭。最简单的方法是:进入设置 > 隐私和安全性 > Windows安全中心 > 病毒和威胁防护 > 管理设置,将实时保护等选项关闭。

5

2026.01.26

2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】
2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】

铁路12306提供起售时间查询、起售提醒、购票预填、候补购票及误购限时免费退票五项服务,并强调官方渠道唯一性与信息安全。

35

2026.01.26

个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

12

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

40

2026.01.26

抖币充值官方网站 抖币性价比充值链接地址
抖币充值官方网站 抖币性价比充值链接地址

网页端充值步骤:打开浏览器,输入https://www.douyin.com,登录账号;点击右上角头像,选择“钱包”;进入“充值中心”,操作和APP端一致。注意:切勿通过第三方链接、二维码充值,谨防受骗

7

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 7.6万人学习

C 教程
C 教程

共75课时 | 4.2万人学习

C++教程
C++教程

共115课时 | 13.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号