您的位置:首页 > 编程语言 > C#

浅析C#中的委托

2015-08-25 10:10 447 查看
委托是寻址方法的.NET版本。在C++中,函数指针只不过是一个指向内存位置的指针,它不是类型安全的。而.NET委托完全不同,委托是安全类型的类,它定义了返回类型和参数的类型。

当把方法传递给其他方法时,需要使用委托。

C#中使用一个类时,分两个阶段。首先需要定义这个类,即告诉编译器这个类由什么组成的。然后,实例化一个对象(除非只使用静态方法)。

对于委托也是类似,也需要两个步骤。首先必须定义要使用的委托,然后必须创建该委托的一个或多个实例。

定义语法:

delegate void IntMethodInoker(int x);
delegate double TwoLongsOp(long first, long second);
delegate string GetString();


定义委托基本上是定义一个新类,所以可以在定义类的任何相同地方定义委托。即可以在另一个类的内部定义,可以在任何类的外部定义,可以在名称空间中把委托定义为顶层对象。

根据委托定义的可见性,和委托的作用域,可以在委托的定义上应用任意常见的访问修饰符:public、private、protected等

例如:

public delegate string GetAString();


使用委托:

private delegate string GetAString();
static void Main()
{
int x=40;
GetAString firstStringMethod = new GetAString(x.ToString);
Console.WriteLine("String is {0}",firstStringMethod () );
}


由上述代码可以看到,C#的委托在语法上总是接受一个参数的构造函数,这个参数就是委托引用的方法,但是这个方法必须匹配最初定义委托时的签名。

实际上,给委托实例提供圆括号与调用委托类的Invoke()方法完全相同。使用Invoke完成一个委托方法的封送,就类似于使用SendMessage方法来给界面线程发送消息,是一个同步方法。也就是说在Invoke封送的方法被执行完毕前,Invoke方法不会返回,从而调用者线程将被阻塞。

因为firstStringMethod 是一个委托类型的变量,所以C#编译器会用firstStringMethod.Invoke()代替firstStringMethod ()。

firstStringMethod();
firstStringMethod.Invoke();


为了减少输入量,只需要委托实例,就可以只传递地址的名称,即委托推断

GetAString firstStringMethod = new GetAString(x.ToString);
GetAString firstStringMethod = x.ToString;


注意:输入行事不能是x.ToString(),也不能把它传给委托变量。x.ToString表示把方法的地址赋予委托变量。

多播委托:

委托可以包含多个方法,这种委托称为多播委托。如果调用多播委托,就可以按顺序连续调用多个方法。但是,委托的签名必须返回void,否则只能得到委托调用的最后一个方法的结果。

多播委托示例程:

delegate void Delegate_Multicast(int x, int y);
Class Class2
{
static void Method1(int x, int y)
{
Console.WriteLine("You r in Method 1");
}
static void Method2(int x, int y)
{
Console.WriteLine("You r in Method 2");
}
public static void Main()
{
Delegate_Multicast func = new Delegate_Multicast(Method1);
func += new Delegate_Multicast(Method2);
func(1,2);             // Method1 and Method2 are called
func -= new Delegate_Multicast(Method1);
func(2,3);             // Only Method2 is called
}
}


解析:

上面的示例程序分别定义了名为method1 和 method2的两个接受整型参数、返回类型为void的方法。

在Main函数里使用下面的声明创建委托对象:

Delegate_Multicast func = new Delegate_Multicast(Method1);

然后使用+= 来添加委托,使用-=来移除委托。

合并委托:

委托对象的一个用途在于,可以使用 + 运算符将它们分配给一个要成为多路广播委托的委托实例。组合的委托可调用组成它的那两个委托。只有相同类型的委托才可以组合。

- 运算符可用来从组合的委托移除组件委托。

delegate void Del(string s);

class TestClass
{
static void Hello(string s)
{
System.Console.WriteLine("  Hello, {0}!", s);
}

static void Goodbye(string s)
{
System.Console.WriteLine("  Goodbye, {0}!", s);
}

static void Main()
{
Del a, b, c, d;

// Create the delegate object a that references
// the method Hello:
a = Hello;

// Create the delegate object b that references
// the method Goodbye:
b = Goodbye;

// The two delegates, a and b, are composed to form c:
c = a + b;

// Remove a from the composed delegate, leaving d,
// which calls only the method Goodbye:
d = c - a;

System.Console.WriteLine("Invoking delegate a:");
a("A");
System.Console.WriteLine("Invoking delegate b:");
b("B");
System.Console.WriteLine("Invoking delegate c:");
c("C");
System.Console.WriteLine("Invoking delegate d:");
d("D");
}
}

/*-------------------------
输出
Invoking delegate a:
Hello, A!
Invoking delegate b:
Goodbye, B!
Invoking delegate c:
Hello, C!
Goodbye, C!
Invoking delegate d:
Goodbye, D!
----------------------*/


匿名方法:

到目前为止,要想使用委托工作,方法必须已经存在。但是还有另一种使用委托的方法:即通过匿名方法。匿名方法是用作委托的参数的一段代码。

用匿名方法定义委托的语法与前面的定义并没有区别。但在实例化的时候就有了区别了。

如果使用匿名方法,则不必创建单独的方法,因此减少了实例化委托所需的编码系统开销。

例如,如果创建方法所需的系统开销是不必要的,在委托的位置指定代码块就非常有用。启动新线程即是一个很好的示例。无需为委托创建更多方法,线程类即可创建一个线程并且包含该线程执行的代码。

void StartThread()
{
System.Threading.Thread t1 = new System.Threading.Thread
(delegate()
{
System.Console.Write("Hello, ");
System.Console.WriteLine("World!");
});
t1.Start();
}


委托类型派生自 .NET Framework 中的 Delegate 类。 委托类型是封装的,它们不能派生出其他类,也不能从 Delegate 派生出自定义类。 由于实例化的委托是一个对象,因此可以作为参数传递或分配给一个属性。 这允许方法作为参数接受委托并在稍后调用委托。 这被称为异步回调,是在长进程完成时通知调用方的常用方法。 当以这种方式使用委托时,使用委托的代码不需要知道要使用的实现方法。 功能类似于封装接口提供的功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: