C#委托

可能很多初学者都听说过委托,但对于委托到底是什么就不得而知了。C#中用关键字delegate(英[ˈdeliɡit,ˈdelɪɡət])生命委托,为此我专门查了一下这个单词的音标和意思解释为:代表;托付。

那么究竟什么是委托呢?我们还是没有说明,我翻了一些书籍,对委托的解释:它是一种数据类型,和引用类型类似,不过和一般的类相比,委托的实例不是在堆中的数据,而是一个方法。委托类似于引用类型,和C++中的函数指针很相似,但是不同之处就在于,他不是存在于堆中的。正是有了委托我们才得以将函数打包成一个变量进行传递。这就是说,我们不止能够将数据作为参数传递,还可以将一个函数作为参数进行传递,这样就可以在需要的时候方便的进行控制的反转(Ioc,控制反转)。

说了那么多没有实际的例子还是理解不了,下面我们通过几个实例来看一下什么是委托:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Delegate
{
class Program
{

public delegate double DelegateOne(double d);//声明一个委托
public static double FunctionOne(double d)
{
return d * 2;
}
static void Main(string[] args)
{
DelegateOne dlgt = new DelegateOne(FunctionOne);//也可以直接DelegateOne dlgt = FunctionOne;
double d=dlgt(3);
Console.WriteLine(d);
Console.ReadKey();
}
}
}

这个例子比较简单,我们首先声明了一个委托DelegateOne,它有一个参数是double类型,返回值也是double类型的。然后定义了一个结构和它类似的方法FunctionOne,参数是double类型返回值也是double类型。在main方法中我们new了一个委托的实例,将FunctionOne传递给它,这就是说实例dlgt就有了FunctionOne的功能(但这里必须保证委托和方法的结构相同)。

下面我们看一下多路广播委托简称多播委托,也就是委托和方法的返回值是void类型。这是我们可以看到这种委托我们可以使用+=和-=来链入和去除多个委托。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Delegate
{
class MulticastDelegate
{
public delegate void DelegateOne(double d);//声明一个委托
public static void FunctionOne(double d)
{
Console.WriteLine(d * 2);
}
public static void FunctionTwo(double d)
{
Console.WriteLine(d * d);
}
static void Main(string[] args)
{
DelegateOne dlgt = new DelegateOne(FunctionOne);
dlgt += new DelegateOne(FunctionTwo);//这就是多播委托的好处
dlgt(3);
Console.ReadKey();
}
}
}

上面这个例子的运行结果是6 9,不是一个结果,而是相当于同时执行了两个方法,这也就是多播委托的特点。我们不仅可以+=一次还可以多次,而且还可以-=多次。我们对上述代码中的Main方法进行稍微的修改:

static void Main(string[] args)
{
DelegateOne dlgt = new DelegateOne(FunctionOne);
dlgt += new DelegateOne(FunctionTwo);//这就是多播委托的好处
dlgt(3);
Console.ReadKey();
dlgt -= new DelegateOne(FunctionTwo);
dlgt(3);
Console.Read();
}

这是的运行结果先是6 9,而后当你按了一个按键之后显示了6.说明什么问题呢,6 9的输出我们上面已经解释过了,因为我们链入了两个方法。后面一个是因为我们去点了一个方法FunctionTwo而只剩下FunctionOne,所以输出6.

多播委托,在教材上是说返回值必须是void,事实上通过实验我们会发现其实如果返回值不是void也可以,只不过这是我我们的就收结果是最后一个链入委托方法的返回值。

我们在前面提到了委托不是存放在堆中的,而是作为一个方法,下面我们具体看看是不是这样:

我们知道,如果是存到了堆中,例如类A和类B(类肯定是在堆中存放的),如果我们另A a=new A(); B b;b=a;这是我们修改b,就可以影响到a。换句话说如果委托也是这样,我们也可以看到这样的结果,那么是不是呢?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Delegate
{
class DelegateNotRef
{
public delegate string DelegateOne();
static void Main(string[] args)
{
int x = 3;
DelegateOne dlgt = new DelegateOne(x.ToString);
Console.WriteLine(dlgt());

x = 4;
Console.WriteLine(dlgt());
Console.WriteLine(x.ToString());
Console.Read();
}
}
}

可以看到,我们输出为3 3 4,而不是3 4 4,说明我们在修改x=4后,委托中的东西并没有随之修改,也就说明了委托不是在堆中存储的。

接下来我们进一步看看泛型委托:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Delegate
{
class GnericDelegate
{
public delegate string DelegateOne(T t,S s);

public static string FunctionOne(string s, int i)
{
return s + i.ToString();
}

public static string FunctionTwo(string s1, string s2)
{
return s1 + s2;
}

static void Main(string[] args)
{
DelegateOne dlgt = new DelegateOne(FunctionOne);
Console.WriteLine(dlgt("ab", 42));

DelegateOne dlgt2 = new DelegateOne(FunctionTwo);
Console.WriteLine(dlgt2("abc","def"));

Console.Read();
}
}
}

很简单,和我们的其他类型的泛型没有多大的差别,这里就不再赘余!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值