delegate problem

  • Thread starter Thread starter karch
  • Start date Start date
K

karch

I can't figure out why this code does not compile - says that 'num' in an
undeclared identifier and that 'delegate':identifier not found. Thoughts?
Help?

void MethodD()
{
List<int>^ data;
BinaryFormatter^ formatter = gcnew BinaryFormatter();
MemoryStream^ stream = gcnew MemoryStream();
data->ForEach(delegate(int num)
{
formatter->Serialize(stream, num);
}
);
};
 
OK, so I now know that anonymous methods (as below) are not supported in
C++/CLI. How then, would one implement the ForEach method of List<> below in
CLI? I have searched the online docs and cant find an example. Thanks again.

\K
 
karch said:
OK, so I now know that anonymous methods (as below) are not supported
in C++/CLI. How then, would one implement the ForEach method of
List<> below in CLI? I have searched the online docs and cant find an
example. Thanks again.

Same way you would in C# 1.1 - the method can't be anonymous (i.e. it must
have a name, and a signature that conforms to the appropriate delegate type,
etc).

-cd
 
Could you give me an example - I've only seen it done with anonymous methods
in C#. And, since generics are new in 2.0, along with the List<>->ForEach
method which takes an Action, I'm not sure how to do this.
 
karch said:
Could you give me an example - I've only seen it done with anonymous
methods in C#. And, since generics are new in 2.0, along with the
List<>->ForEach method which takes an Action, I'm not sure how to do this.

Well, since your anonymous delegate references local variables (technically
a "closure"), it's a little more complicated. You'd do something like this:

// Sample

public ref class X
{
ref class Capture
{
private:
BinaryFormatter^ _formatter;
MemoryStream^ _stream;

public:
Capture(BinaryFormatter^ formatter, MemoryStream^ stream)
: _formatter(formatter), _stream(stream)
{
}

void Action(int n)
{
_formatter->Serialize(_stream,n);
}
};

public:
void IterateList()
{
List<int>^ data;
BinaryFormatter^ formatter = gcnew BinaryFormatter();
MemoryStream^ stream = gcnew MemoryStream();
Capture c(formatter,stream);
data->ForEach(gcnew Action<int>(%c,&Capture::Action));
}
};

// End of sample

The class Capture binds the two local variables to member variables so
they're accessible to the Action function. If formatter and stream were
already members of the class containing IterateList (MethodD in your
example), then you wouldn't need that intermediate capture class.

Under the covers, the C# compiler implements something very similar to this
when you write an anonymous method, automatically generating captures for
local variables (and hoisting local variables of value-type to the GC heap
so that the closure can modify them too). Pretty handy mechanism, isn't it?
Maybe some day C++ will have closures, but that day isn't today.

-cd
 
Thanks Carl. Great explanation - yes, I guess I never really appreciated the
power of anonymous methods to the extent that I should.:-)

(and thanks for the code sample, as well - its always easier to see code in
action)
 
Back
Top