F2 + F1
/*7b*/ cd3 -= cd1 + cd1; // F1 + F2 + F2 + F1
cd3(60);
}
System::Delegate
代理类型的定义,会隐式地创建一个对应的类(class)类型,并且所有的代理类型均从类库System::Delegate继承而来。要定义一个这样的类,唯一的方法就是通过delegate上下文关键字。代理类为隐式的sealed,因此它们不能被用作基类。另外,一个非代理类也不能从System::Delegate继承。
例6演示了几个Delegate函数的用法:
例6:
using namespace System;
delegate void D(int x);
ref class Test
{
String^ objName;
public:
Test(String^ objName)
{
this->objName = objName;
}
void M(int i)
{
Console::WriteLine("Object {0}: {1}", objName, i);
}
};
void ProcessList(D^ del, int value, Object^ objToExclude);
int main()
{
/*1*/ Test^ t1 = gcnew Test("t1");
D^ cd1 = gcnew D(t1, &Test::M);
/*2*/ Test^ t2 = gcnew Test("t2");
D^ cd2 = gcnew D(t2, &Test::M);
/*3*/ Test^ t3 = gcnew Test("t3");
D^ cd3 = gcnew D(t3, &Test::M);
/*4*/ D^ list = cd1 + cd2 + cd3 + cd2;
/*5a*/ ProcessList(list, 100, nullptr);
/*5b*/ ProcessList(list, 200, t1);
/*5c*/ ProcessList(list, 300, t2);
/*6a*/ D^ cd4 = cd1 + cd2;
/*6b*/ D^ cd5 = (D^)cd4->Clone();
/*6c*/ ProcessList(cd4, 5, nullptr);
/*6d*/ ProcessList(cd5, 6, nullptr);
}
void ProcessList(D^ del, int value, Object^ objToExclude)
{
/*7*/ if (del == nullptr)
{
return;
}
/*8*/ else if (objToExclude == nullptr)
{
del(value);
}
else
{
/*9*/ array<Delegate^>^ delegateList = del->GetInvocationList();
for each (Delegate^ d in delegateList)
{
/*10*/ if (d->Target != objToExclude)
{
/*11*/ ((D^)d)(value);
}
}
}
}
实例函数Test::M与代理类型D相兼容,当调用时,这个函数只是识别出它调用的对象,并带有一个整数参数。
在标号1、2、3中,定义了三个Test类型的对象,并把它们各自与实例函数Test:M包装在单独的代理类型D中。接着,在标号4中,创建了一个四入口的调用列表。
倘若传递进来的调用列表不为空,ProcessList函数将调用在列表中除了特定对象以外的所有函数,例如,在标号5a中,没有排除任何入口,因此所有的函数都会被调用;在标号5b中,t1被排除在外,而标号5c中,与对象t2有关的两个入口都被排除了,结果输出如下:
Object t1: 100
Object t2: 100
Object t3: 100
Object t2: 100
Object t2: 200
Object t3: 200
Object t2: 200
Object t1: 300
Object t3: 300
在标号6b中,调用了Clone创建了代理cd4的一个副本,这个函数返回一个Object^,因此,要把它转换成D^类型。当原始及克隆的代理在标号6c、6d中调用时,结果输出如下:
Object t1: 5
Object t2: 5
Object t1: 6
Object t2: 6
关于函数ProcessList,如果参数中的代理实例为nullptr,即没有调用列表,那它将直接返回;如果排除的对象为nullptr,那么列表中所有的函数都将被调用;如果存在要排除的对象,就要像标号8中那样把调用列表当作代理数组取出,接着,在标号9中逐个排查不相符的入口,最后,在标号10中调用余下的这些函数。尽管在调用列表中每个入口都是Del类型,但GetInvocationList返回一个基类Delegate数组,所以在调用每个代理实例之前,需像标号10那样先转换成类型D。
事件
在C++/ |