The Unbound Delegates
An unbound delegate allows you to pass an instance of the type whose function you want to call when the delegate is called. Unbound delegates are especially useful if you want to iterate through the objects in a collection (using for each, in) keywords, and call a member function on each instance. The following is a summary of how to declare, instantiate, and call bound and unbound delegates:
| Action | Bound Delegates | Unbound Delegates |
| Declare | The delegate signature must match the signature of the function you want to call through the delegate. | The first parameter of the delegate signature is the type of this for the object you want to call. After the first parameter, the delegate signature must match the signature of the function you want to call through the delegate. |
| Instantiate | When you instantiate a bound delegate, you can specify an instance function or a global or static member function. To specify an instance function, the first parameter is an instance of the type whose member function you want to call and the second parameter is the address of the function you want to call. If you want to call a global or static member function, you only pass the name of the static member function or the name of a global function. | When instantiating an unbound delegate, you only pass the address of the function you want to call. |
| Call | When you call a bound delegate, you only pass the parameters required by the delegate signature. | Same as a bound delegate (but remember the first parameter must be an instance of the object containing the function you want to call). |
|
Table 3 | ||
The following code sample demonstrates the syntax for declaring, instantiating, and calling unbound delegates.
// unbound delegates
// compile with: /clr
#include "stdafx.h"
using namespace System;
ref struct DeleStrucRef
{
DeleStrucRef(){}
DeleStrucRef(int i) : m_i(i) {}
void Print(int i) { System::Console::WriteLine("Ref, m_i + i = {0}", m_i + i);}
private:
int m_i;
};
value struct DeleStrucVal
{
void Print() { System::Console::WriteLine("Value, m_i = {0}", m_i);}
int m_i;
};
delegate void Delegate1(DeleStrucRef^, int i);
delegate void Delegate2(DeleStrucRef%, int i);
delegate void Delegate3(interior_ptr<DeleStrucVal>);
delegate void Delegate4(DeleStrucVal%);
delegate void Delegate5(int i);
delegate void Delegate6();
int main(array<System::String ^> ^args)
{
DeleStrucRef^ newobj1 = gcnew DeleStrucRef(1);
DeleStrucRef% newobj2 = *gcnew DeleStrucRef(2);
Delegate1 ^ Unbound_Delegate1 = gcnew Delegate1(&DeleStrucRef::Print);
// delegate takes a handle
Unbound_Delegate1(newobj1, 1);
Unbound_Delegate1(%newobj2, 1);
Delegate2 ^ Unbound_Delegate2 = gcnew Delegate2(&DeleStrucRef::Print);
// delegate takes a tracking reference (must deference the handle)
Unbound_Delegate2(*newobj1, 1);
Unbound_Delegate2(newobj2, 1);
// instantiate a bound delegate to an instance member function
Delegate5 ^ Bound_Del = gcnew Delegate5(newobj1, &DeleStrucRef::Print);
Bound_Del(1);
// instantiate value types
DeleStrucVal val1 = {7};
DeleStrucVal val2 = {8};
Delegate3 ^ Unbound_Delegate3 = gcnew Delegate3(&DeleStrucVal::Print);
Unbound_Delegate3(&val1);
Unbound_Delegate3(&val2);
Delegate4 ^ Unbound_Delegate4 = gcnew Delegate4(&DeleStrucVal::Print);
Unbound_Delegate4(val1);
Unbound_Delegate4(val2);
Delegate6 ^ Bound_Delegate3 = gcnew Delegate6(val1, &DeleStrucVal::Print);
Bound_Delegate3();
return 0;
}
Output:

The following program sample shows how you can use unbound delegates and the for each, in keywords to iterate through objects in a collection and call a member function on each instance.
// unbound delegates
// compile with: /clr
#include "stdafx.h"
using namespace System;
ref class RefClass
{
String^ MyStr;
public:
RefClass(String^ str) : MyStr(str) {}
void Print() { Console::Write(MyStr); }
};
delegate void PrintDelegate(RefClass^);
int main()
{
PrintDelegate^ newdel = gcnew PrintDelegate(&RefClass::Print);
array< RefClass^ >^ newarrayobj = gcnew array<RefClass^>(10);
for (int i = 0; i < newarrayobj->Length; ++i)
newarrayobj[i] = gcnew RefClass(i.ToString());
for each (RefClass^ RefCl in newarrayobj)
newdel(RefCl);
Console::WriteLine();
return 0;
}
Output:

The following program sample creates an unbound delegate to a property's accessor functions.
// unbound delegates
// compile with: /clr
#include "stdafx.h"
using namespace System;
ref struct RefStruc
{
property int P1
{
int get() { return m_i; }
void set(int i) { m_i = i; }
}
private:
int m_i;
};
delegate void DelBSet(RefStruc^, int);
delegate int DelBGet(RefStruc^);
int main()
{
RefStruc^ newobj = gcnew RefStruc;
DelBSet^ delBSet = gcnew DelBSet(&RefStruc::P1::set);
delBSet(newobj, 100);
DelBGet^ delBGet = gcnew DelBGet(&RefStruc::P1::get);
Console::Write("Get...set value: ");
System::Console::WriteLine(delBGet(newobj));
return 0;
}
Output:

The following code sample shows how to invoke a multicast delegate, where one instance is bound and one instance is unbound.
|

The following program sample shows how to create and call an unbound generic delegate.
// unbound delegates
// compile with: /clr
#include "stdafx.h"
using namespace System;
ref struct RefStruc
{
RefStruc(int i) : m_i(i) {}
int funct(RefStruc ^) { return 999; }
int funct() { return m_i + 5; }
int m_i;
};
value struct ValStruc
{
int funct(ValStruc%) { return 999; }
int funct() { return m_i + 5; }
int m_i;
};
generic <typename Typ>
delegate int Del(Typ mytyp);
generic <typename Typ>
delegate int DelV(Typ% mytyp);
int main(array<System::String ^> ^args)
{
RefStruc^ newobj = gcnew RefStruc(7);
System::Console::WriteLine("Ref: {0}", (gcnew Del<RefStruc^>(&RefStruc::funct))(newobj));
ValStruc val;
val.m_i = 9;
System::Console::WriteLine("Value: {0}", (gcnew DelV<ValStruc >(&ValStruc::funct))(val) );
return 0;
}
Output:
