469,603 Members | 2,100 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,603 developers. It's quick & easy.

very strange effect with anonymous delegates (.net 2.0)

I have a very funny/strange effect here.

if I let the delegate do "return
prop.GetGetMethod().Invoke(info.AudioHeader, null);"
then I get wrong results, that is, a wrong method is called and I have no
clue why.
But if I store the MethodInfo in a local variable I works as expected.

I do not understand why this is so, shouldn't both ways be semantically
equal?

foreach (PropertyInfo prop in typeof(Au.AuHeader).GetProperties())
{
ColumnInfo col = ColumnInfoFromProperty(prop);

// very strange effect: If I do not store MethodInfo here in a local
variable,
// but instead call prop.GetGetMethod() directly from the delegate I get
wrong results
MethodInfo mi = prop.GetGetMethod();

col.SortValue = delegate(FileInformation info) { return
mi.Invoke(info.AudioHeader, null); };

cols.Add(col);
}
Nov 17 '05 #1
5 1503
"cody" <de********@gmx.de> wrote in message
news:ec**************@TK2MSFTNGP14.phx.gbl...
I have a very funny/strange effect here.

if I let the delegate do "return
prop.GetGetMethod().Invoke(info.AudioHeader, null);"
then I get wrong results, that is, a wrong method is called and I have no
clue why.
But if I store the MethodInfo in a local variable I works as expected.

I do not understand why this is so, shouldn't both ways be semantically
equal?

foreach (PropertyInfo prop in typeof(Au.AuHeader).GetProperties())
{
ColumnInfo col = ColumnInfoFromProperty(prop);

// very strange effect: If I do not store MethodInfo here in a local
variable,
// but instead call prop.GetGetMethod() directly from the delegate I
get wrong results
MethodInfo mi = prop.GetGetMethod();

col.SortValue = delegate(FileInformation info) { return
mi.Invoke(info.AudioHeader, null); };

cols.Add(col);
}


Ahh the wonders of anonymous delegates and closures.

Have you had a look at what the IL looks like for a method with an anonymous
delegate? You get a generated class and all data that is accessed from the
enclosing scope become members of that class.

In the first case prop becomes a member of the class in the second mi does.
Do you see the problem? prop changes on each iteration, therefore you end up
creating a delegate referring to the place where the iterator got to when
the delegete fired.

In the second, each mi is local to each iteration so the delegate gets the
correct property

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk
Nov 17 '05 #2
>>I have a very funny/strange effect here.

if I let the delegate do "return
prop.GetGetMethod().Invoke(info.AudioHeader, null);"
then I get wrong results, that is, a wrong method is called and I have no
clue why.
But if I store the MethodInfo in a local variable I works as expected.

I do not understand why this is so, shouldn't both ways be semantically
equal?

foreach (PropertyInfo prop in typeof(Au.AuHeader).GetProperties())
{
ColumnInfo col = ColumnInfoFromProperty(prop);

// very strange effect: If I do not store MethodInfo here in a local
variable,
// but instead call prop.GetGetMethod() directly from the delegate I
get wrong results
MethodInfo mi = prop.GetGetMethod();

col.SortValue = delegate(FileInformation info) { return
mi.Invoke(info.AudioHeader, null); };

cols.Add(col);
}


Ahh the wonders of anonymous delegates and closures.

Have you had a look at what the IL looks like for a method with an
anonymous delegate? You get a generated class and all data that is
accessed from the enclosing scope become members of that class.

In the first case prop becomes a member of the class in the second mi
does. Do you see the problem? prop changes on each iteration, therefore
you end up creating a delegate referring to the place where the iterator
got to when the delegete fired.

In the second, each mi is local to each iteration so the delegate gets the
correct property


Sorry, maybe Iam stupid, but I still do not see the difference.
Both mi and prop are local variables which are 'lifted' to a field, right
when
the delegate is created. So there shouldn't be any difference, should it?
Nov 17 '05 #3
"cody" <de********@gmx.de> wrote in message
news:OS**************@TK2MSFTNGP12.phx.gbl...
I have a very funny/strange effect here.

if I let the delegate do "return
prop.GetGetMethod().Invoke(info.AudioHeader, null);"
then I get wrong results, that is, a wrong method is called and I have
no clue why.
But if I store the MethodInfo in a local variable I works as expected.

I do not understand why this is so, shouldn't both ways be semantically
equal?

foreach (PropertyInfo prop in typeof(Au.AuHeader).GetProperties())
{
ColumnInfo col = ColumnInfoFromProperty(prop);

// very strange effect: If I do not store MethodInfo here in a local
variable,
// but instead call prop.GetGetMethod() directly from the delegate I
get wrong results
MethodInfo mi = prop.GetGetMethod();

col.SortValue = delegate(FileInformation info) { return
mi.Invoke(info.AudioHeader, null); };

cols.Add(col);
}


Ahh the wonders of anonymous delegates and closures.

Have you had a look at what the IL looks like for a method with an
anonymous delegate? You get a generated class and all data that is
accessed from the enclosing scope become members of that class.

In the first case prop becomes a member of the class in the second mi
does. Do you see the problem? prop changes on each iteration, therefore
you end up creating a delegate referring to the place where the iterator
got to when the delegete fired.

In the second, each mi is local to each iteration so the delegate gets
the correct property


Sorry, maybe Iam stupid, but I still do not see the difference.
Both mi and prop are local variables which are 'lifted' to a field, right
when
the delegate is created. So there shouldn't be any difference, should it?


But prop is changing every time around the loop, mi is local to the loop and
so is fixed for each iteration.

If you look at the generated code (e.g in reflector) you will see that in
the case of using the iterator, the generated class is instantiated once
outside of the loop as that is the scope of the iterator.

In the case of the local variable, the generated class is instantiated
inside the loop as that is the scope of mi.#

So for the iterator the single integer value ends up as the last iterated
one, for the local variable its each value is captured in a separate
instance.

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

Nov 17 '05 #4
Ok I had a look in reflector and I now see the problem. Since in generated
code there is no local variable "PropertyInfo prop" but instead just a call
to "enumerable.Current" so there is nothing to 'lift'.

This maybe right from the view of the ILCode but it is toally wrong from the
view of the sourcecode since "PropertyInfo prop" is a readonly variable from
the programmer's view.

Iam the opinion that is is a very dangerous pitfall. If MS won't fix that,
they should at least throw a compiler error when a foreach iterator is used
in a anonymous method.

What do you think about that?

"Richard Blewett [DevelopMentor]" <richard at nospam dotnetconsult dot co
dot uk> schrieb im Newsbeitrag news:ez**************@TK2MSFTNGP10.phx.gbl...
"cody" <de********@gmx.de> wrote in message
news:OS**************@TK2MSFTNGP12.phx.gbl...
I have a very funny/strange effect here.

if I let the delegate do "return
prop.GetGetMethod().Invoke(info.AudioHeader, null);"
then I get wrong results, that is, a wrong method is called and I have
no clue why.
But if I store the MethodInfo in a local variable I works as expected.

I do not understand why this is so, shouldn't both ways be semantically
equal?

foreach (PropertyInfo prop in typeof(Au.AuHeader).GetProperties())
{
ColumnInfo col = ColumnInfoFromProperty(prop);

// very strange effect: If I do not store MethodInfo here in a local
variable,
// but instead call prop.GetGetMethod() directly from the delegate I
get wrong results
MethodInfo mi = prop.GetGetMethod();

col.SortValue = delegate(FileInformation info) { return
mi.Invoke(info.AudioHeader, null); };

cols.Add(col);
}

Ahh the wonders of anonymous delegates and closures.

Have you had a look at what the IL looks like for a method with an
anonymous delegate? You get a generated class and all data that is
accessed from the enclosing scope become members of that class.

In the first case prop becomes a member of the class in the second mi
does. Do you see the problem? prop changes on each iteration, therefore
you end up creating a delegate referring to the place where the iterator
got to when the delegete fired.

In the second, each mi is local to each iteration so the delegate gets
the correct property


Sorry, maybe Iam stupid, but I still do not see the difference.
Both mi and prop are local variables which are 'lifted' to a field, right
when
the delegate is created. So there shouldn't be any difference, should it?


But prop is changing every time around the loop, mi is local to the loop
and so is fixed for each iteration.

If you look at the generated code (e.g in reflector) you will see that in
the case of using the iterator, the generated class is instantiated once
outside of the loop as that is the scope of the iterator.

In the case of the local variable, the generated class is instantiated
inside the loop as that is the scope of mi.#

So for the iterator the single integer value ends up as the last iterated
one, for the local variable its each value is captured in a separate
instance.

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

Nov 17 '05 #5
"cody" <de********@gmx.de> wrote in message
news:Ow**************@TK2MSFTNGP12.phx.gbl...
Ok I had a look in reflector and I now see the problem. Since in generated
code there is no local variable "PropertyInfo prop" but instead just a
call to "enumerable.Current" so there is nothing to 'lift'.

This maybe right from the view of the ILCode but it is toally wrong from
the view of the sourcecode since "PropertyInfo prop" is a readonly
variable from the programmer's view.

Iam the opinion that is is a very dangerous pitfall. If MS won't fix that,
they should at least throw a compiler error when a foreach iterator is
used in a anonymous method.

What do you think about that?


Surely its simply following standard scoping rules - its declaring the class
at the outermost scope of the local variables that are used within the anon
delegate. It obviously can't do it within the scope as the outermost one
wouldn't be in scope at that point.

So what you are asking for is special casing of your situation (I'm not
lambasting you for this just stating what you are asking). This is an
equally valid construct:

int i = 0;
int[] ii = int[3] { 1, 2, 3};

foreach ( i in ii )
{
// blah
}

this has basically the same scope as your iterator version - what would you
have the compiler do here?

I can understand your frustration, the closure like feature of anon
delegates can lead to some weird behavior if you don't know whats ahppening
behind the scenes. But asking fofr compiler special casig of your construct
is alot to ask (but it has been done before)

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk
Nov 17 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

6 posts views Thread by Werner Partner | last post: by
2 posts views Thread by Marcos Stefanakopolus | last post: by
3 posts views Thread by anonymous | last post: by
4 posts views Thread by Harold Howe | last post: by
4 posts views Thread by Frankie | last post: by
reply views Thread by devrayhaan | last post: by
reply views Thread by gheharukoh7 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.