匿名方法的由来
我们在这里用事件的定义来举例,没有匿名方法的时候
public
partial
class
_Default : System.Web.UI.Page
{
protected void Page_Load( object sender, EventArgs e)
{
addButton.Click += new EventHandler(addClick);
}
protected void addClick( object sender, EventArgs e)
{
listBox.Items.Add(textBox.Text);
}
}
{
protected void Page_Load( object sender, EventArgs e)
{
addButton.Click += new EventHandler(addClick);
}
protected void addClick( object sender, EventArgs e)
{
listBox.Items.Add(textBox.Text);
}
}
有了匿名方法以后
public
partial
class
_Default : System.Web.UI.Page
{
protected void Page_Load( object sender, EventArgs e)
{
addButton.Click += delegate {
listBox.Items.Add(textBox.Text);
};
}
}
{
protected void Page_Load( object sender, EventArgs e)
{
addButton.Click += delegate {
listBox.Items.Add(textBox.Text);
};
}
}
匿名方法的简介
1.匿名方法允许我们以一种"内联"的方式编写方法代码,将代码直接与委托实例相关联,从而使得委托实例化的工作变得更加直观和方便
2.匿名方法的几个相关问题
-匿名方法的参数
a.匿名方法可以在delegate关键字后跟一个
参数列表(如果方法体没用到参数可以不指定),后面的代码块则可以访问这些参数。
b.
参数列表必须与
使用匿名方法的委托的参数列表完全相同。
带参数的匿名方法
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//delegate void EventHanddler(object sender,EventArgs e);
//注意委托与匿名方法的参数列表
addButton.Click += delegate(object sender1,EventArgs e1) {
listBox.Items.Add(textBox.Text);
};
//如果方法体中没有用到参数列表的参数的话,一般省略不写,如下:
addButton.Click += delegate
{
listBox.Items.Add(textBox.Text);
};
//下面的写法是错误的,除非委托本身没有参数列表
addButton.Click += delegate()
{
listBox.Items.Add(textBox.Text);
};
}
}
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//delegate void EventHanddler(object sender,EventArgs e);
//注意委托与匿名方法的参数列表
addButton.Click += delegate(object sender1,EventArgs e1) {
listBox.Items.Add(textBox.Text);
};
//如果方法体中没有用到参数列表的参数的话,一般省略不写,如下:
addButton.Click += delegate
{
listBox.Items.Add(textBox.Text);
};
//下面的写法是错误的,除非委托本身没有参数列表
addButton.Click += delegate()
{
listBox.Items.Add(textBox.Text);
};
}
}
-匿名方法的返回值
a.如果委托类型的返回值为void,那么匿名方法就不能有返回值
b.如果委托类型的返回值不为void,那么匿名方法的返回值就必须与委托类型的返回值类型一致。
如下示例
delegate
void MyDelegate();
MyDelegate g = delegate{
......
return;//也可忽略不写
}
delegate
int MyDelegate();
MyDelegate g= delegate{
......
return 100;
}
-外部变量
a.一些局部变量和参数有可能被匿名方法所使用,它们被称为"匿名方法的外部变量"。
b.外部变量的生存期会由于匿名方法"捕获效应"而延长,一直延长到委托实例不被引用为止。
delegate
double
Function();
static void CustomFunction( double data)
{
Function f = delegate {
data += 0.2 ;
return data;
};
}
static void CustomFunction( double data)
{
Function f = delegate {
data += 0.2 ;
return data;
};
}
委托类型的推断
1.C#2.0允许我们在进行委托实例化时,省略掉委托类型,而直接采用方法名,C#编译器会做合理的推断
2.由于C#2.0有了委托类型推断功能,所以2.0针对1.0有如下改变
在1.0中
addButton.Click += new EventHanddler(AddClick);
Apply(a,new Function(Math.Sin));
在2.0中
addButton.Click += AddClick;
Apply(a,Math.Sin);
匿名方法机制
1.C#2.0中的匿名方法仅仅是通过编译器的一层而外处理,来简化委托实例化的工作。它与以前版本不存在根本性的差别。
2.深入了解匿名方法机制
-静态方法中的匿名方法
public delegate void D();
static void F(){
D d = delegate{
Console.WriteLine("test");
}
}
上面的代码将被编译器转换为如下代码
static void F(){
D d = new D(_Method1);
}
static void _Method1(){
Console.WriteLine("test");
}
-实例化方法中的匿名方法
class Test
{
int x;
void F()
{
D d = delegate{Console.WriteLine(this.x);};
}
}
上面的代码被编译器转换为
void F()
{
D d = new D(_Method1);
}
void _Method1()
{
Console.WriteLine(this.x);
}
-匿名方法中的外部变量
void F()
{
int y = 123;
D d = delegate{Console.WriteLine(y)};
}
上面的代码被编译器转换为
class _Temp
{
public int y;
public void _Method1()
{
Console.WriteLine(y);
}
}
void F()
{
_Temp t = new _Temp();
t.y=123;
D d = new D(t._Method1);
}
迭代器
在没有迭代器之前,创建一个可用于foreach的集合,如下做法
2.0以前版本实现可foreach的集合
public class MyCollections : IEnumerable
{
public MyEnumerator GetEnumerator()
{
return new MyEnumerator();
}
public class MyEnumerator : IEnumerator
{
public void Reset()
{
//
}
public bool MoveNext()
{
//
}
public int Current
{
get
{
//
}
}
object IEnumerator.Current
{
get
{
//
}
}
}
}
public class MyCollections : IEnumerable
{
public MyEnumerator GetEnumerator()
{
return new MyEnumerator();
}
public class MyEnumerator : IEnumerator
{
public void Reset()
{
//
}
public bool MoveNext()
{
//
}
public int Current
{
get
{
//
}
}
object IEnumerator.Current
{
get
{
//
}
}
}
}
C#2.0中使用迭代器定义可foreach的集合
用迭代器生成可foreach的集合
public class Stack : IEnumerable
{
int[] item = { 4,1,9,7,6,8,10};
public IEnumerator GetEnumerator()
{
for (int i = 0; i < item.Length; i++)
{
//用yield return语句产生枚举元素
yield return item[i];
}
}
}
public class Stack : IEnumerable
{
int[] item = { 4,1,9,7,6,8,10};
public IEnumerator GetEnumerator()
{
for (int i = 0; i < item.Length; i++)
{
//用yield return语句产生枚举元素
yield return item[i];
}
}
}
用迭代器生成可foreach的集合(含中断迭代)
public class Stack : IEnumerable
{
int[] item = { 4,1,9,7,6,8,10};
public IEnumerator GetEnumerator()
{
for (int i = 0; i < item.Length; i++)
{
//用yield break语句中断迭代
if (item[i] > 8)
{
yield break;
}
yield return item[i];
}
}
}
public class Stack : IEnumerable
{
int[] item = { 4,1,9,7,6,8,10};
public IEnumerator GetEnumerator()
{
for (int i = 0; i < item.Length; i++)
{
//用yield break语句中断迭代
if (item[i] > 8)
{
yield break;
}
yield return item[i];
}
}
}
测试实例
public partial class Demo1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Stack stack = new Stack();
foreach (int i in stack)
{
Response.Write(i);
}
}
}
public partial class Demo1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Stack stack = new Stack();
foreach (int i in stack)
{
Response.Write(i);
}
}
}
注意上图中含有yield break;语句的测试结果为
4,1