在<关于“回调”的实现>一文中,我们探讨了使用委托实现回调。但对于回调的原型来讲,我们感到其使用上的繁琐,本文我们使用“匿名”方法来对其简化。
我们首先回顾一下,实现回调的主要步骤:
1、定义委托
2、定义调用者
3、定义执行体函数
我们来看下,通过匿名方法--对回调一文中的完整示例进行语法简化后的--程序如下:
using System; using System.Collections; class DBConnection { protected static int NextConnectionNbr = 1; protected string connectionName; public string ConnectionName { get { return connectionName; } } public DBConnection() { connectionName = "Database Connection " + DBConnection.NextConnectionNbr++; } } class DBManager { protected ArrayList activeConnections; public DBManager() { activeConnections = new ArrayList(); for (int i = 1; i < 6; i++) { activeConnections.Add(new DBConnection()); } } public delegate void EnumConnectionsCallback(DBConnection connection); public void EnumConnections(EnumConnectionsCallback callback) { foreach (DBConnection connection in activeConnections) { callback(connection); } } }; class InstanceDelegate { /*不再需要函数定义 public static void PrintConnections(DBConnection connection) { Console.WriteLine("[InstanceDelegate.PrintConnections] {0}", connection.ConnectionName); }*/ public static void Main() { DBManager dbManager = new DBManager(); Console.WriteLine("[Main] Instantiating the " + "delegate method"); /* DBManager.EnumConnectionsCallback _printConnections = new DBManager.EnumConnectionsCallback(PrintConnections);*/ //替换如下 DBManager.EnumConnectionsCallback _printConnections = delegate(DBConnection connection){ Console.WriteLine("[InstanceDelegate.PrintConnections] {0}", connection.ConnectionName); } Console.WriteLine("[Main] Calling EnumConnections " + "- passing the delegate"); dbManager.EnumConnections(_printConnections); Console.ReadLine(); } };
小结:
我们看到,于委托中忽略了函数名称的函数代码块,被称作anonymous method,即匿名方法。既然委托是同构函数的归类,就没有必要再为函数声明进行定义,所以,匿名方法凸显了委托的意义、简化了委托的使用。--匿名方法不需要使用函数名的原因是编译器会自动为delegate关键字处理函数名,而programmer并不需要这个函数名,而且有无意义不是很大。
更进一步,既然委托可以被“看作”对同类函数的语法抽象,我们可以用匿名方法忽略函数定义的header,那么我们当然可以忽略函数的名称而只保留参数,这就是“lambda语句”在委托中的应用。见实例:
using System; using System.Collections; class DBConnection { protected static int NextConnectionNbr = 1; protected string connectionName; public string ConnectionName { get { return connectionName; } } public DBConnection() { connectionName = "Database Connection " + DBConnection.NextConnectionNbr++; } } class DBManager { protected ArrayList activeConnections; public DBManager() { activeConnections = new ArrayList(); for (int i = 1; i < 6; i++) { activeConnections.Add(new DBConnection()); } } public delegate void EnumConnectionsCallback(DBConnection connection); public void EnumConnections(EnumConnectionsCallback callback) { foreach (DBConnection connection in activeConnections) { callback(connection); } } }; class InstanceDelegate { public static void Main() { DBManager dbManager = new DBManager(); Console.WriteLine("[Main] Instantiating the " + "delegate method"); /* DBManager.EnumConnectionsCallback _printConnections = delegate(DBConnection connection){ Console.WriteLine("[InstanceDelegate.PrintConnections] {0}", connection.ConnectionName);*/ //替换如下 DBManager.EnumConnectionsCallback _printConnections = connection=>{ Console.WriteLine("[InstanceDelegate.PrintConnections] {0}", connection.ConnectionName); } Console.WriteLine("[Main] Calling EnumConnections " + "- passing the delegate"); dbManager.EnumConnections(_printConnections); Console.ReadLine(); } };
小结:lambda的引入,产生了变量超出其范围而与委托的生存周期同步这一“现象”,这里我们暂称这种变量为外部变量(outer variable),这时系统不再视变量为固定的而是可移动的,但可使用fixed关键词来控制(fixed关键词的使用见后)。
最后,我们通过引入泛型来对该程序进行性能优化,示例如下:
using System; using System.Collections; using System.Collections.Generic; class DBConnection { protected static int NextConnectionNbr = 1; protected string connectionName; public string ConnectionName { get { return connectionName; } } public DBConnection() { connectionName = "Database Connection " + DBConnection.NextConnectionNbr++; } } class DBManager<T> { protected ArrayList activeConnections; public DBManager() { activeConnections = new ArrayList(); for (int i = 1; i < 6; i++) { activeConnections.Add(new DBConnection()); } } public delegate void EnumConnectionsCallback(T connection); public void EnumConnections(EnumConnectionsCallback callback) { foreach (T connection in activeConnections) { callback(connection); } } }; class InstanceDelegate { public static void Main() { DBManager dbManager = new DBManager(); Console.WriteLine("[Main] Instantiating the " + "delegate method"); DBManager.EnumConnectionsCallback _printConnections = connection=>{ Console.WriteLine("[InstanceDelegate.PrintConnections] {0}", connection.ConnectionName); } Console.WriteLine("[Main] Calling EnumConnections " + "- passing the delegate"); dbManager.EnumConnections(_printConnections); Console.ReadLine(); } };
小结:通过对DBManger引进泛型,使得负责数据库连接的DBConnection与委托部分的程序相分离。 这就是所谓的“泛型委托”。
总结:由此,我们通过“委托推理”(delegate inference)、“匿名方法”(anonymous method)、“lambda表达式(type inference)”,基本完成了回调一文中回调原型的简化。 效果就是取得客户端代码最优化,这也意味着良好的易读性。而lambda最重要的意义在于实现了算法复用(algorithm reusing),MS建议使用lambda取代匿名方法。
附,fixed keyword的使用
fixed 语句禁止垃圾回收器重定位可移动的变量。fixed 语句只能出现在不安全的上下文中。Fixed 还可用于创建固定大小的缓冲区。
fixed 语句设置指向托管变量的指针并在 statement 执行期间“钉住”该变量。如果没有 fixed 语句,则指向可移动托管变量的指针的作用很小,因为垃圾回收可能不可预知地重定位变量。C# 编译器只允许在 fixed 语句中分配指向托管变量的指针。
// assume class Point { public int x, y; }
// pt is a managed variable, subject to garbage collection.
Point pt = new Point();
// Using fixed allows the address of pt members to be
// taken, and "pins" pt so it isn't relocated.
fixed ( int* p = &pt.x )
{
*p = 1;
}
可以用数组或字符串的地址初始化指针:
fixed (int* p = arr) ... // equivalent to p = &arr[0]
har* p = str) ... // equivalent to p = &str[0]
只要指针的类型相同,就可以初始化多个指针:
fixed (byte* ps = srcarray, pd = dstarray) {...}
要初始化不同类型的指针,只需嵌套 fixed 语句:
fixed (int* p1 = &p.x)
{
d (double* p2 = &array[5])
{
// Do something with p1 and p2.
}
}
执行完语句中的代码后,任何固定变量都被解除固定并受垃圾回收的制约。因此,不要指向 fixed 语句之外的那些变量。
无法修改在 fixed 语句中初始化的指针。
在不安全模式中,可以在堆栈上分配内存。堆栈不受垃圾回收的制约,因此不需要被锁定。
// statements_fixed.cs
// compile with: /unsafe
using System;
class Point
{
public int x, y;
}
class FixedTest
{
// Unsafe method: takes a pointer to an int.
unsafe static void SquarePtrParam (int* p)
{
*p *= *p;
}
unsafe static void Main()
{
Point pt = new Point();
pt.x = 5;
pt.y = 6;
// Pin pt in place:
fixed (int* p = &pt.x)
{
SquarePtrParam (p);
}
// pt now unpinned
Console.WriteLine ("{0} {1}", pt.x, pt.y);
}
}
结果为:
25 6
发表评论
-
ZT,一篇好文
2010-05-03 10:33 1001读读语言大牛们(其中有位是Anders)这篇文章,会很受益。( ... -
effective hierarchy(二)之 函数合辑(2)
2009-09-16 21:29 727介绍: 本节我们来看看另外一种封装,构建件。构建件作为 ... -
effective hierarchy(二)之 函数合辑(1)
2009-08-19 14:53 781“暴露”阶段:值-> ... -
effective hierarchy(一)之 基本概念(8)
2009-07-02 23:39 686MSDN,C#2 一、语句 1.结束点和可达性(en ... -
effective hierarchy(一)之 基本概念结束篇
2009-06-30 15:41 664一、函数/功能成员(fun ... -
effective hierarchy(一)之 基本概念(7)
2009-06-23 21:15 937以下可跳过: [立记保留:到现在为止,我满意的是认真的精神。 ... -
effective hierarchy(一)之 基本概念(6)
2009-06-21 00:34 951MSDN,C#2.0 转换(conversions) ... -
effective hierarchy(一)之 基本概念(5)
2009-06-18 22:16 717MSDN,C#2.0 变量基本点: 变量代表 ... -
effective hierarchy(一)之 基本概念(4)
2009-06-15 15:59 728MSDN,C#2.0: 一、名字空间和类型名称(nam ... -
effective hierarchy(一)之 基本概念(3)
2009-06-14 15:00 732MSDN,C#2.0: 一、签 ... -
effective hierarchy(一)之 基本概念(2)
2009-06-13 18:22 828MSDN:基本概念 一、 ... -
effective hierarchy(一) 之基本概念(1)
2009-06-11 09:37 780我告诫自己,不要忽略简单的东西,又要扎实。所以这一篇开始,专门 ... -
effective hierarchy(一)之 属性与索引器
2009-06-07 14:07 1152编程笺言:“优良的设计 ... -
effective hierarchy(一)之 从array说起(4)
2009-06-07 00:53 805回顾:上一节中,我们 ... -
effective hierarchy(一)之 从array说起(3)
2009-06-06 21:20 702回顾: 从上一节中,可以看出枚举的易用性对数组使用的启示意义 ... -
effective hierarchy(一)之 从array说起(2)
2009-06-06 09:34 691复习: 从上一节,可 ... -
effective hierarchy(一)之 从array说起(1)
2009-05-29 13:59 892MSDN(c#2.0): 数组的元义是 ... -
effective hierarchy(一)之 C#中的new
2009-05-27 23:21 841MSDN(c#2.0): 在msdn中,指出new的三种用法。 ...
相关推荐
事件源通过`+=`操作符订阅事件处理程序,将委托实例与事件处理方法关联起来。例如,对于一个按钮点击事件: ```csharp this.button1.Click += new System.EventHandler(this.button1_Click); ``` 在这段代码中,`...
"匿名方法"与Lambda表达式类似,但不使用lambda操作符。它是在没有定义名称的情况下创建的方法,通常作为参数传递给其他方法。例如,`delegate(int x, int y) { return x + y; }` 是一个匿名方法,实现了加法操作。 ...
Lambda表达式使用“=>”操作符,左边是输入参数(如果有的话),右边是表达式或语句块。Lambda表达式可以与委托紧密结合,尤其在LINQ查询中广泛使用。 Lambda表达式的基本语法如下: ```csharp (input parameters) ...
Lambda表达式不能作为`is`和`as`操作符的左侧,也不能在不安全的上下文中使用。 7. **与匿名方法的比较** Lambda表达式相比于匿名方法更简洁,因为它们不需要`delegate`关键字和花括号(对于单行Lambda)。同时,...
所有的 Lambda 表达式都使用操作符“=>“,表示“goes to (转变为)”。 Lambda 表达式简介 Lambda 表达式是一个包含若干表达式和语句的匿名函数。可以被用作创建委托对象或表达式树类型。所有的 Lambda 表达式都...
- Lambda 表达式必须与函数式接口关联,因为它们代表了接口的一个实现。函数式接口是指只有一个抽象方法的接口,例如 `java.util.function.Function` 和 `java.util.Comparator`。 3. **Lambda 实例** - 对于...
Lambda 表达式的概念包含两个主要部分:参数列表(左侧)和函数体(右侧),两者之间由 Lambda 操作符 "->" 分隔。参数列表可以为空,也可以包含一个或多个参数,根据情况可以省略括号。函数体可以是单个表达式或一...
4. **三元操作符与Lambda**: Lambda表达式可以替代简单的条件表达式,比如 `(a, b) -> a > b ? a : b` 可以用于比较两个数的大小。 5. **并行流与Lambda**: Java 8的Stream API支持并行处理,通过`parallel...
5. 匿名内部类与Lambda的对比:在Java 8之前,我们通常通过匿名内部类来实现函数式接口。Lambda表达式则提供了更简洁的写法,减少了代码量,提升了可读性。 6. 方法引用和构造器引用:Lambda表达式还可以直接引用已...
`java.util.stream.Stream` API提供了丰富的操作符,如`map`, `filter`, `reduce`, `forEach`等,这些操作符可以配合Lambda表达式处理集合,实现数据流的处理。例如: ```java List<String> names = Arrays.asList...
在提供的"PPTX"文件"Lambda表达式与LINQ.pptx"中,可能会详细解释Lambda表达式的语法、用法和实际示例,以及如何在C++中实现类似LINQ的查询方式。通过学习这个文件,你可以进一步加深对这两个主题的理解,并将它们...
例如,使用Lambda表达式可以实现匿名函数、函数对象、闭包等高级编程概念。 在实际应用中,Lambda表达式可以用来实现各种函数式编程的需求,如图形处理、数据分析、算法实现等等。同时,Lambda表达式也可以与STL算...
答案:可以使用 Lambda 表达式来实现 Director 接口的抽象方法 makeMovie。 10. 请使用 Lambda 表达式在 Test 中完成调用 Calculator 接口。 答案:可以使用 Lambda 表达式来实现 Calculator 接口的抽象方法 calc...
Lambda表达式的应用远远不止这些,它们可以与LINQ的各种操作符结合,如`Where`, `SelectMany`, `Any`, `All`, `Count`, `Max`, `Min`等,实现复杂的数据过滤、转换和聚合。同时,Lambda表达式也是C#异步编程的重要...
Lambda表达式可以被看作是匿名函数,即没有名字的函数,它能够简洁地表示只包含单个抽象方法的接口实例。在"stream"的概念下,Lambda表达式与Java Stream API结合,为开发者提供了强大的数据处理能力。 "Stream"是...
2. **可定制化操作**:库提供了自定义操作符的功能,用户可以定义自己的操作符,与现有的Lambda函数结合使用,增强了代码的灵活性。 3. **函数组合**:允许将多个Lambda函数合并为一个,减少代码重复,提高代码复用...
事件通常使用私有的多播委托来实现,而`+=`和`-=`操作符用于订阅和取消订阅事件: ```csharp public event MyDelegate MyEvent; public void RaiseEvent() { if (MyEvent != null) { MyEvent(10, 20); // 调用...
Lambda表达式是一种简洁地表示匿名函数的方法,即一个无需名字的函数。它允许开发者将函数作为程序的一部分来使用,这种能力在函数式编程语言中十分常见。在Java 8中,Lambda表达式可以被赋值给变量、作为参数传递给...