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++)

{

    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));

你写对了么?

时间: 2024-09-20 05:54:53

C# 从函数到委托的相关文章

高阶函数、委托与匿名方法

高阶函数(higher-order function)是指把另一个函数作为参数或返回值的函数.例如 在JavaScript语言中,Function是顶级类型.一个函数就是类型为 Function的顶级对象,自 然就可以作为另一个函数的参数或返回值.例如在Microsoft AJAX Library(ASP.NET AJAX 的客户端类库)中有一个被广泛使用的createDelegate方法.该方法接受一个对象A和一个函 数F作为参数,并返回一个函数R.当调用函 数R时,F函数将被调用,并且保证无

JavaScript匿名函数与委托使用示例_基础知识

<html xmlns="http://www.w3.org/1999/xhtml"> <head> <!-- C#匿名函数--> <title></title> <script type="text/javascript"> var f1 = function (x, y) { //[1] 定义一个匿名函数,用变量f1来指向它(f1相当于一个委托,这个时候f1就可以当做一个函数来用了) ret

成员函数指针与高性能的C++委托 (Member Function Pointers and the Fastest Possible C++ Delegates)

标准C++中没有真正的面向对象的函数指针.这一点对C++来说是不幸的,因为面向对象的指针(也叫做"闭包(closure)"或"委托(delegate)")在一些语言中已经证明了它宝贵的价值.在Delphi (Object Pascal)中,面向对象的函数指针是Borland可视化组建库(VCL,Visual Component Library)的基础.而在目前,C#使"委托"的概念日趋流行,这也正显示出C#这种语言的成功.在很多应用程序中,&qu

c#委托和事件的具体使用,和回调函数该怎么用,哈希表是怎么回事?

问题描述 c#委托和事件的具体使用,和回调函数该怎么用,哈希表是怎么回事? c#委托和事件的具体使用,和回调函数该怎么用,哈希表是怎么回事? 解决方案 http://www.cnblogs.com/OpenCoder/archive/2009/09/23/1572646.htmlhttp://www.cnblogs.com/xpvincent/archive/2013/01/15/2860841.html 解决方案二: 你还是别问了,你好好看看msdn,或者自己网上查查,都能找到答案 解决方案三

ASP.NET深入浅出系列4- 也谈委托和事件

一.委托的定义: <高级汉语大词典>中是如下解释的:托付给别的人或机构办理.要说生活中的意思其实大家都能理解,无非是"当某人(机构)需要完成一件自己不能或不应该完成的事情的时候,此人(机构)物色一个合适的且有能力完成此事的人选,然后提供必要的信息,将此事委托给物色到的人(机构)来完成." C#中的委托是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为,委托方法的使用可以像其他任何方法一样具有参数和返回值.委托对象能被传递给调用该方法引用的代码而无须

委托,事件

问题描述 请教下使用委托,和使用事件调用委托的好处,在项目里什么情况下用,最好能给个例子,谢谢 解决方案 解决方案二:事件和委托可以提供回调功能从而降低耦合或者完全解耦.委托的一个例子,可以通过函数参数传递委托来实现回调,而不用关心最终的输出对象在什么地方http://blog.csdn.net/jinjazz/archive/2008/05/07/2413039.aspx事件的一个例子,和委托类似http://blog.csdn.net/jinjazz/archive/2008/05/06/2

C#中怎么创建一个类的动态属性或者动态函数名

问题描述 问题描述:在一个C#的类A内,怎么创建类A的动态属性或者动态函数名?例如,A类内,外界传入一个stringcourse[]数组,要在A类内,把course[i]的不同字符串变成A类的属性名,或者变成A类的函数名(i=0,1,2,....). 解决方案 解决方案二:这是不能够实现的,而且也没有理由需要这样做,只是存值和取值,实现功能的方法很多,不必计较形式解决方案三:意义何在?解决方案四:使用dynamic类型.解决方案五:函数可以使用委托字段代替.解决方案六:哦哦,谢谢.解决方案七:哦

求助:C#动态调用DLL的,为什么getProcAddress无法获得NATIVE DLL中的导出函数?

问题描述 ①自己用C++写了个DLL在其中声明了一个导出函数extern"C"__declspec(dllexport)LRESULTCALLBACKhookProc(intnCode,WPARAMwParam,LPARAMlParam){//实现内容忽略return1;} 生成DLL后,因为是C++编译器编译的,会改变方法名,于是我用了VIEWDLL查看了导出函数名称叫_hookProc@12②调用DLL代码[DllImport("kernel32.dll",Ch

Filter组件开发中的SDK基类分析

DirectShow SDK提供了一套开发Filter的基类源代码.基于这些基类开发Filter将大大简化开发过程. 1.CBaseObject 大部分SDK类都从CBaseObject类(参见combase.h)中继承而来的. [cpp] view plaincopy class CBaseObject   {      private:          // Disable the copy constructor and assignment by default so you will