C# 从函数到委托

简介: 原文地址:http://bbs.csdn.net/topics/390784442 看这样的程序: C# code? 1 2 3 4 5 6 7 8 9 10 11 12 int sum = 0; for (int i = 1; i <= 100; i++)

原文地址:http://bbs.csdn.net/topics/390784442

看这样的程序:


C# code ?
1
2
3
4
5
6
7
8
9
10
11
12
int  sum = 0;
for  ( int  i = 1; i <= 100; i++)
{
     sum = sum + i;
}
Console.WriteLine(sum);
sum = 0;
for  ( int  i = 1; i <= 1000; i++)
{
     sum = sum + i;
}
Console.WriteLine(sum);


这个程序有一点点呆,很明显程序的前半部分和后半部分拥有类似的结构,只是控制i的循环变量的终值不同。因此我们可以提取出一个函数:

C# code ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static  void  Main( string [] args)
{
     Console.WriteLine(Sum(100));
     Console.WriteLine(Sum(1000));
}
 
static  int  Sum( int  n)
{
     int  sum = 0;
     for  ( int  i = 1; i <= n; i++)
     {
         sum = sum + i;
     }
     return  sum;
}

现在我们需要统计1~100中所有偶数的和,怎么做呢?很简单,加上一个判断:

C# code ?
1
2
3
4
5
6
int  sum = 0;
for  ( int  i = 1; i <= 100; i++)
{
     if  (i % 2 == 0) sum = sum + i;
}
Console.WriteLine(sum);


这个程序和那个Sum函数的结构还是类似的,我们能不能写出一个通用的函数呢?有的人不假思索地这么写:

C# code ?
1
2
3
4
5
6
7
8
9
10
11
12
static  int  Sum( int  n,  int  type)
{
     int  sum = 0;
     for  ( int  i = 1; i <= n; i++)
     {
         if  (type == 1)
         { sum = sum + i; }
         if  (type == 2)
         if  (i % 2 == 0) sum = sum + i; }
     }
     return  sum;
}

这样type传1就可以累加所有的数字,传2只累加偶数。

那么现在要累加奇数怎么办呢?再加一个type=3吧。如果要累加质数呢?……你开始抱怨,需求怎么能这么多呢。

我们再仔细看下代码,我们发现,这些需求虽然都有差异,但是程序中唯一变化的只有循环体中的判断。我们有没有办法将这个判断作为参数传进去呢?如果可以,那么问题似乎就解决了。

委托就是这样一种类型,它这种类型代表一段代码,使得我们可以将它作为参数传给函数,函数将它放入那个需要变化的地方执行,从而允许我们作为调用者来自定义函数的一些行为。

C# code ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
delegate  bool  PredicateDelegate( int  n);  // 定义委托
 
static  bool  foo1( int  n)
{
     return  true ;
}
 
static  bool  foo2( int  n)  // 将Sum函数中可变的代码抽取出来作为一个函数
{
     return  n % 2 == 0;
}
 
static  void  Main( string [] args)
{
     Console.WriteLine(Sum(100, foo2));  // 将函数作为参数传给Sum
}
 
static  int  Sum( int  n, PredicateDelegate pred)
{
     int  sum = 0;
     for  ( int  i = 1; i <= n; i++)
     {
         if  (pred(i)) sum = sum + i;  // 将委托的代码放在原先的位置上
     }
     return  sum;
}


当我们传入foo2,那么Sum只累加偶数,如果传入foo1,那么Sum全部累加。如果只累加奇数呢?我们只要定义一个函数:

C# code ?
1
bool  foo3( int  n) {  return  n % 2 != 0; }


即可。
请注意,foo1 foo2 foo3虽然和 Sum 写在一起,但是在这里,我们将它视为函数的调用者定义的,而不是编写Sum的那个人定义的。我们可以无限扩展。编写出foo4 foo5……,从而实现各种不同的需求。

fooN 这个函数有什么特点呢?它们是为了给Sum提供参数而临时定义的,事实上,我们也不打算在别的地方再利用它,那么这个函数的函数名作为实参其实没有什么用,所以C#提供了一种更简单的写法:

C# code ?
1
Console.WriteLine(Sum(100,  delegate ( int  n) {  return  n % 2 == 0; }));


在这里,我们将foo2这个函数的定义合并到了对Sum的调用中,它看上去更像一个参数。

还不够简单?也许你觉得已经很简单了,但是的确C#提供了更简单的写法,那就是Lambda表达式:它的写法是

(参数列表) => { 语句体 }

当语句体中的语句只有1行,并且是 return 表达式; 这样的形式的时候,我们可以省略花括号,直接写表达式。更cool的是,Lambda可以自动推定参数的类型,于是int n中的int也省下了。

C# code ?
1
Console.WriteLine(Sum(100, (n) => n % 2 == 0));


C#还特别规定,当参数只有1个的时候,括号也可以省略,所以上面的代码的最终形式可以表示成:

C# code ?
1
Console.WriteLine(Sum(100, n => n % 2 == 0));


思考下,我们对foo1如何改写?

C# code ?
1
Console.WriteLine(Sum(100, n =>  true ));


你写对了么?
相关文章
|
JavaScript 前端开发 Java
javascript实现像java、c#之类的sleep暂停的函数功能
javascript实现像java、c#之类的sleep暂停的函数功能
72 0
|
2月前
|
C# Python
使用wxpython开发跨平台桌面应用,对wxpython控件实现类似C#扩展函数处理的探究
【10月更文挑战第30天】使用 `wxPython` 开发跨平台桌面应用时,可以通过创建辅助类来模拟 C# 扩展函数的功能。具体步骤包括:1. 创建辅助类 `WxWidgetHelpers`;2. 在该类中定义静态方法,如 `set_button_color`;3. 在应用中调用这些方法。这种方法提高了代码的可读性和可维护性,无需修改 `wxPython` 库即可为控件添加自定义功能。但需要注意显式调用方法和避免命名冲突。
|
4月前
|
C#
C#一分钟浅谈:委托与事件的实现方式
本文详细介绍了C#编程中委托与事件的基础知识及应用场景。首先解释了委托的概念,包括定义与使用方法;接着介绍了事件这一基于委托的特殊类型,展示了如何在类中定义事件及跨类订阅与处理事件;最后讨论了常见问题如事件未处理异常、重复订阅及内存泄漏等,并提出了相应的解决方案。通过本文,读者将全面掌握委托与事件的使用技巧,提升应用程序的设计与开发水平。
155 7
|
5月前
|
编译器 C#
C#中内置的泛型委托Func与Action
C#中内置的泛型委托Func与Action
74 4
|
5月前
|
C#
C#中的委托(一)
C#中的委托(一)
42 1
|
5月前
|
C# C++
C#语言进阶(一)—委托
C#语言进阶(一)—委托
56 0
|
8月前
|
存储 安全 C#
C# - 委托与事件
这篇文档介绍了C#中的委托和事件。委托是存储方法引用的类型,支持回调、事件处理,具有引用方法、类型安全、多播性等特性,并在异步编程中发挥作用。事件是委托的封装,提供保护和订阅机制,防止外部直接访问。当需要在类内部控制方法调用,防止外部误触发时,可使用事件。
|
7月前
|
开发框架 .NET 程序员
掌握C#语言的精髓:基础知识与实用技能详解(数据类型与变量+ 条件与循环+函数与模块+LINQ+异常+OOP)
掌握C#语言的精髓:基础知识与实用技能详解(数据类型与变量+ 条件与循环+函数与模块+LINQ+异常+OOP)
39 0
|
7月前
|
C#
C#||委托和事件的实例
C#||委托和事件的实例