By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
439,971 Members | 1,467 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 439,971 IT Pros & Developers. It's quick & easy.

Delegates vs. MethodInfo When Calling Code Dynamically

P: n/a
I've been led to believe by several articles, particularly Eric Gunnerson's
C# Calling Code Dynamically, that calling a method dynamically through
Reflection was much slower than through a Delegate. My testing showed that
actually it was six times faster: 0.5 seconds for 100,000 iterations versus
3.1 seconds.

Can anyone explain why? Something in the way I coded it? I'd appreciate
any insights.

Here's the code (in a Windows Form with two buttons). Operating system is
Windows XP Pro. Visual Studio 2005. .Net Framework 2.0.

const string OP_GREATER_THAN_OR_EQUAL = "op_GreaterThanOrEqual";
const string OP_LESS_THAN_OR_EQUAL = "op_LessThanOrEqual";
const decimal TEST_VAL = 100000.00M;
const decimal BENCHMARK_VAL = 101000.00M;
const int TEST_LIMIT = 100000;

private delegate bool OperatorTest( decimal pTestVal, decimal pBenchmarkVal );

private void btnMethodInfo_Click( object sender, EventArgs e ){
DateTime start = DateTime.Now;
for( int i = 0; i < TEST_LIMIT; i++ )
{
Type t1 = TEST_VAL.GetType();
Type t2 = BENCHMARK_VAL.GetType();
MethodInfo mi = typeof( decimal ).GetMethod(
OP_GREATER_THAN_OR_EQUAL, new Type[] { t1, t2 } );
bool isValid = ( bool )mi.Invoke( null, new object[] { TEST_VAL,
BENCHMARK_VAL } );
}
DateTime stop = DateTime.Now;
Console.WriteLine( "Elapsed time by MethodInfo = " + ( stop- start ) );
}

private void btnDelegate_Click( object sender, EventArgs e ){
DateTime start = DateTime.Now;
for( int i = 0; i < TEST_LIMIT; i++ )
{
Delegate d = Delegate.CreateDelegate( typeof( OperatorTest ), typeof(
decimal ), OP_GREATER_THAN_OR_EQUAL );
bool isValid = ( bool )d.DynamicInvoke( new object[] { TEST_VAL,
BENCHMARK_VAL } );
}
DateTime stop = DateTime.Now;
Console.WriteLine( "Elapsed time by Delegate = " + ( stop - start ) );
}

--
Tom Corcoran
Nov 9 '07 #1
Share this Question
Share on Google+
15 Replies


P: n/a
I think you need to go back and revisit your code. Your delegate is being
created multiple times inside the loop, and this is eating up CPU cycles.
Only need to create the delegate one time. Haven't looked further, but there
could be other gotchas too.
-- Peter
http://www.eggheadcafe.com
unBlog: http://petesbloggerama.blogspot.com
BlogMetaFinder: http://www.blogmetafinder.com

"Tom Corcoran" wrote:
I've been led to believe by several articles, particularly Eric Gunnerson's
C# Calling Code Dynamically, that calling a method dynamically through
Reflection was much slower than through a Delegate. My testing showed that
actually it was six times faster: 0.5 seconds for 100,000 iterations versus
3.1 seconds.

Can anyone explain why? Something in the way I coded it? I'd appreciate
any insights.

Here's the code (in a Windows Form with two buttons). Operating system is
Windows XP Pro. Visual Studio 2005. .Net Framework 2.0.

const string OP_GREATER_THAN_OR_EQUAL = "op_GreaterThanOrEqual";
const string OP_LESS_THAN_OR_EQUAL = "op_LessThanOrEqual";
const decimal TEST_VAL = 100000.00M;
const decimal BENCHMARK_VAL = 101000.00M;
const int TEST_LIMIT = 100000;

private delegate bool OperatorTest( decimal pTestVal, decimal pBenchmarkVal );

private void btnMethodInfo_Click( object sender, EventArgs e ){
DateTime start = DateTime.Now;
for( int i = 0; i < TEST_LIMIT; i++ )
{
Type t1 = TEST_VAL.GetType();
Type t2 = BENCHMARK_VAL.GetType();
MethodInfo mi = typeof( decimal ).GetMethod(
OP_GREATER_THAN_OR_EQUAL, new Type[] { t1, t2 } );
bool isValid = ( bool )mi.Invoke( null, new object[] { TEST_VAL,
BENCHMARK_VAL } );
}
DateTime stop = DateTime.Now;
Console.WriteLine( "Elapsed time by MethodInfo = " + ( stop- start ) );
}

private void btnDelegate_Click( object sender, EventArgs e ){
DateTime start = DateTime.Now;
for( int i = 0; i < TEST_LIMIT; i++ )
{
Delegate d = Delegate.CreateDelegate( typeof( OperatorTest ), typeof(
decimal ), OP_GREATER_THAN_OR_EQUAL );
bool isValid = ( bool )d.DynamicInvoke( new object[] { TEST_VAL,
BENCHMARK_VAL } );
}
DateTime stop = DateTime.Now;
Console.WriteLine( "Elapsed time by Delegate = " + ( stop - start ) );
}

--
Tom Corcoran
Nov 9 '07 #2

P: n/a
I see a few other things going on here.

First, you (the OP) should be using the Stopwatch class in the
System.Diagnostics namespace to perform the timing. It will provide a much
more accurate result than the DateTime class.

Regarding the loop that calls through reflection, every iteration
through the loop is getting the decimal type three times, and then getting
the method, and then calling the method. You want to test just calling the
method, not all those other things. To that end, the code in that event
handler should look like this:

private void btnMethodInfo_Click( object sender, EventArgs e )
{
// The stopwatch instance.
Stopwatch sw = new Stopwatch();

// Get the type of decimal.
Type decimalType = typeof(decimal);

// Get the method info.
MethodInfo mi = decimalType.GetMethod(OP_GREATER_THAN_OR_EQUAL, new Type[]
{ decimalType, decimalType });

// NOW start the timer.
sw.Start();

// Iterate.
for( int i = 0; i < TEST_LIMIT; i++ )
{
// Invoke the method.
bool isValid = (bool) mi.Invoke(null, new object[] { TEST_VAL,
BENCHMARK_VAL } );
}

// Stop the timer.
sw.Stop();

// Write the result.
Console.WriteLine( "Elapsed time by MethodInfo = " + sw.Elapsed );
}

Regarding the loop that calls through the delegate, most of what applies
in the other method applies here. You only need to create the delegate
once, the types once, etc, etc:

private void btnDelegate_Click( object sender, EventArgs e )
{
// The stopwatch instance.
Stopwatch sw = new Stopwatch();

// Get the delegate.
Delegate d = Delegate.CreateDelegate(typeof(OperatorTest), typeof(decimal),
OP_GREATER_THAN_OR_EQUAL);

// NOW start the timer.
sw.Start();

// Iterate.
for( int i = 0; i < TEST_LIMIT; i++ )
{
// Invoke the delegate.
bool isValid = (bool) d.DynamicInvoke(new object[] { TEST_VAL,
BENCHMARK_VAL } );
}

// Stop the stopwatch.
sw.Stop();

// Output the result.
Console.WriteLine("Elapsed time by Delegate = " + sw.Elapsed);
}

I think that doing it this way will produce very different (and
expected) results for the OP.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Peter Bromberg [C# MVP]" <pb*******@yahoo.NoSpamMaam.comwrote in message
news:AF**********************************@microsof t.com...
>I think you need to go back and revisit your code. Your delegate is being
created multiple times inside the loop, and this is eating up CPU cycles.
Only need to create the delegate one time. Haven't looked further, but
there
could be other gotchas too.
-- Peter
http://www.eggheadcafe.com
unBlog: http://petesbloggerama.blogspot.com
BlogMetaFinder: http://www.blogmetafinder.com

"Tom Corcoran" wrote:
>I've been led to believe by several articles, particularly Eric
Gunnerson's
C# Calling Code Dynamically, that calling a method dynamically through
Reflection was much slower than through a Delegate. My testing showed
that
actually it was six times faster: 0.5 seconds for 100,000 iterations
versus
3.1 seconds.

Can anyone explain why? Something in the way I coded it? I'd appreciate
any insights.

Here's the code (in a Windows Form with two buttons). Operating system
is
Windows XP Pro. Visual Studio 2005. .Net Framework 2.0.

const string OP_GREATER_THAN_OR_EQUAL = "op_GreaterThanOrEqual";
const string OP_LESS_THAN_OR_EQUAL = "op_LessThanOrEqual";
const decimal TEST_VAL = 100000.00M;
const decimal BENCHMARK_VAL = 101000.00M;
const int TEST_LIMIT = 100000;

private delegate bool OperatorTest( decimal pTestVal, decimal
pBenchmarkVal );

private void btnMethodInfo_Click( object sender, EventArgs e ){
DateTime start = DateTime.Now;
for( int i = 0; i < TEST_LIMIT; i++ )
{
Type t1 = TEST_VAL.GetType();
Type t2 = BENCHMARK_VAL.GetType();
MethodInfo mi = typeof( decimal ).GetMethod(
OP_GREATER_THAN_OR_EQUAL, new Type[] { t1, t2 } );
bool isValid = ( bool )mi.Invoke( null, new object[] { TEST_VAL,
BENCHMARK_VAL } );
}
DateTime stop = DateTime.Now;
Console.WriteLine( "Elapsed time by MethodInfo = " + ( stop-
start ) );
}

private void btnDelegate_Click( object sender, EventArgs e ){
DateTime start = DateTime.Now;
for( int i = 0; i < TEST_LIMIT; i++ )
{
Delegate d = Delegate.CreateDelegate( typeof( OperatorTest ),
typeof(
decimal ), OP_GREATER_THAN_OR_EQUAL );
bool isValid = ( bool )d.DynamicInvoke( new object[] { TEST_VAL,
BENCHMARK_VAL } );
}
DateTime stop = DateTime.Now;
Console.WriteLine( "Elapsed time by Delegate = " + ( stop - start ) );
}

--
Tom Corcoran
Nov 10 '07 #3

P: n/a
Nicholas and Peter, thank you both very much. Nicholas, thank you in
particular for taking the time to code a better version and for teaching me
about Stopwatch. Using your code and Stopwatch, the elapsed time of the
Delegates method was still about 3.5 times SLOWER than that of the MethodInfo
method. This seems counter to all that I have heard about Reflection and
Delegates. I'd appreciate any other ideas you might have, as I'm putting a
change into an Xml web service that will likely get a high traffic needing a
dynamically called comparison operator.
--
Tom Corcoran
"Nicholas Paldino [.NET/C# MVP]" wrote:
I see a few other things going on here.

First, you (the OP) should be using the Stopwatch class in the
System.Diagnostics namespace to perform the timing. It will provide a much
more accurate result than the DateTime class.

Regarding the loop that calls through reflection, every iteration
through the loop is getting the decimal type three times, and then getting
the method, and then calling the method. You want to test just calling the
method, not all those other things. To that end, the code in that event
handler should look like this:

private void btnMethodInfo_Click( object sender, EventArgs e )
{
// The stopwatch instance.
Stopwatch sw = new Stopwatch();

// Get the type of decimal.
Type decimalType = typeof(decimal);

// Get the method info.
MethodInfo mi = decimalType.GetMethod(OP_GREATER_THAN_OR_EQUAL, new Type[]
{ decimalType, decimalType });

// NOW start the timer.
sw.Start();

// Iterate.
for( int i = 0; i < TEST_LIMIT; i++ )
{
// Invoke the method.
bool isValid = (bool) mi.Invoke(null, new object[] { TEST_VAL,
BENCHMARK_VAL } );
}

// Stop the timer.
sw.Stop();

// Write the result.
Console.WriteLine( "Elapsed time by MethodInfo = " + sw.Elapsed );
}

Regarding the loop that calls through the delegate, most of what applies
in the other method applies here. You only need to create the delegate
once, the types once, etc, etc:

private void btnDelegate_Click( object sender, EventArgs e )
{
// The stopwatch instance.
Stopwatch sw = new Stopwatch();

// Get the delegate.
Delegate d = Delegate.CreateDelegate(typeof(OperatorTest), typeof(decimal),
OP_GREATER_THAN_OR_EQUAL);

// NOW start the timer.
sw.Start();

// Iterate.
for( int i = 0; i < TEST_LIMIT; i++ )
{
// Invoke the delegate.
bool isValid = (bool) d.DynamicInvoke(new object[] { TEST_VAL,
BENCHMARK_VAL } );
}

// Stop the stopwatch.
sw.Stop();

// Output the result.
Console.WriteLine("Elapsed time by Delegate = " + sw.Elapsed);
}

I think that doing it this way will produce very different (and
expected) results for the OP.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Peter Bromberg [C# MVP]" <pb*******@yahoo.NoSpamMaam.comwrote in message
news:AF**********************************@microsof t.com...
I think you need to go back and revisit your code. Your delegate is being
created multiple times inside the loop, and this is eating up CPU cycles.
Only need to create the delegate one time. Haven't looked further, but
there
could be other gotchas too.
-- Peter
http://www.eggheadcafe.com
unBlog: http://petesbloggerama.blogspot.com
BlogMetaFinder: http://www.blogmetafinder.com

"Tom Corcoran" wrote:
I've been led to believe by several articles, particularly Eric
Gunnerson's
C# Calling Code Dynamically, that calling a method dynamically through
Reflection was much slower than through a Delegate. My testing showed
that
actually it was six times faster: 0.5 seconds for 100,000 iterations
versus
3.1 seconds.

Can anyone explain why? Something in the way I coded it? I'd appreciate
any insights.

Here's the code (in a Windows Form with two buttons). Operating system
is
Windows XP Pro. Visual Studio 2005. .Net Framework 2.0.

const string OP_GREATER_THAN_OR_EQUAL = "op_GreaterThanOrEqual";
const string OP_LESS_THAN_OR_EQUAL = "op_LessThanOrEqual";
const decimal TEST_VAL = 100000.00M;
const decimal BENCHMARK_VAL = 101000.00M;
const int TEST_LIMIT = 100000;

private delegate bool OperatorTest( decimal pTestVal, decimal
pBenchmarkVal );

private void btnMethodInfo_Click( object sender, EventArgs e ){
DateTime start = DateTime.Now;
for( int i = 0; i < TEST_LIMIT; i++ )
{
Type t1 = TEST_VAL.GetType();
Type t2 = BENCHMARK_VAL.GetType();
MethodInfo mi = typeof( decimal ).GetMethod(
OP_GREATER_THAN_OR_EQUAL, new Type[] { t1, t2 } );
bool isValid = ( bool )mi.Invoke( null, new object[] { TEST_VAL,
BENCHMARK_VAL } );
}
DateTime stop = DateTime.Now;
Console.WriteLine( "Elapsed time by MethodInfo = " + ( stop-
start ) );
}

private void btnDelegate_Click( object sender, EventArgs e ){
DateTime start = DateTime.Now;
for( int i = 0; i < TEST_LIMIT; i++ )
{
Delegate d = Delegate.CreateDelegate( typeof( OperatorTest ),
typeof(
decimal ), OP_GREATER_THAN_OR_EQUAL );
bool isValid = ( bool )d.DynamicInvoke( new object[] { TEST_VAL,
BENCHMARK_VAL } );
}
DateTime stop = DateTime.Now;
Console.WriteLine( "Elapsed time by Delegate = " + ( stop - start ) );
}

--
Tom Corcoran
Nov 12 '07 #4

P: n/a
On Nov 12, 1:50 pm, Tom Corcoran
<TomCorco...@discussions.microsoft.comwrote:
Nicholas and Peter, thank you both very much. Nicholas, thank you in
particular for taking the time to code a better version and for teaching me
about Stopwatch. Using your code and Stopwatch, the elapsed time of the
Delegates method was still about 3.5 times SLOWER than that of the MethodInfo
method. This seems counter to all that I have heard about Reflection and
Delegates. I'd appreciate any other ideas you might have, as I'm putting a
change into an Xml web service that will likely get a high traffic needing a
dynamically called comparison operator.
Could you show your new complete code? It would be useful to have a
copy that we can run ourselves. Was your timing performed within the
debugger or not?

Jon

Nov 12 '07 #5

P: n/a
Jon,

Thanks for your reply. Here is the new code as rewritten by Nicholas. The
timing was performed within the debugger.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace DelegatesProblem
{
public partial class Form1 : Form
{
const string OP_GREATER_THAN_OR_EQUAL = "op_GreaterThanOrEqual";
const string OP_LESS_THAN_OR_EQUAL = "op_LessThanOrEqual";
const decimal TEST_VAL = 100000.00M;
const decimal BENCHMARK_VAL = 101000.00M;
const int TEST_LIMIT = 100000;

private delegate bool OperatorTest( decimal pTestVal, decimal
pBenchmarkVal );

public Form1()
{
InitializeComponent();
}

private void btnMethodInfo_Click( object sender, EventArgs e )
{
this.Cursor = Cursors.WaitCursor;
Stopwatch sw = new Stopwatch();
Type decimalType = typeof( decimal );
MethodInfo mi = decimalType.GetMethod(OP_GREATER_THAN_OR_EQUAL,
new Type[]{decimalType, decimalType} );
sw.Start();
for( int i = 0; i < TEST_LIMIT; i++ )
{
bool isValid = ( bool )mi.Invoke( null, new object[] {
TEST_VAL, BENCHMARK_VAL } );
}
sw.Stop();
Console.WriteLine( "Elapsed time by MethodInfo = " + sw.Elapsed );
this.Cursor = Cursors.Default;
}

private void btnDelegate_Click( object sender, EventArgs e )
{
this.Cursor = Cursors.WaitCursor;
Stopwatch sw = new Stopwatch();
Delegate d = Delegate.CreateDelegate( typeof( OperatorTest ),
typeof( decimal ), OP_GREATER_THAN_OR_EQUAL );
sw.Start();
for( int i = 0; i < TEST_LIMIT; i++ )
{
bool isValid = ( bool )d.DynamicInvoke( new object[] {
TEST_VAL, BENCHMARK_VAL } );
}
sw.Stop();
Console.WriteLine( "Elapsed time by Delegate = " + sw.Elapsed );
this.Cursor = Cursors.Default;
}

private void btnDone_Click( object sender, EventArgs e )
{
this.Close();
this.Dispose();
}
}
}
--
Tom Corcoran
"Jon Skeet [C# MVP]" wrote:
On Nov 12, 1:50 pm, Tom Corcoran
<TomCorco...@discussions.microsoft.comwrote:
Nicholas and Peter, thank you both very much. Nicholas, thank you in
particular for taking the time to code a better version and for teaching me
about Stopwatch. Using your code and Stopwatch, the elapsed time of the
Delegates method was still about 3.5 times SLOWER than that of the MethodInfo
method. This seems counter to all that I have heard about Reflection and
Delegates. I'd appreciate any other ideas you might have, as I'm putting a
change into an Xml web service that will likely get a high traffic needing a
dynamically called comparison operator.

Could you show your new complete code? It would be useful to have a
copy that we can run ourselves. Was your timing performed within the
debugger or not?

Jon

Nov 12 '07 #6

P: n/a
On Nov 12, 2:11 pm, Tom Corcoran
<TomCorco...@discussions.microsoft.comwrote:
Thanks for your reply. Here is the new code as rewritten by Nicholas. The
timing was performed within the debugger.
Four things:

1) Code within a Windows Form (or any MarshalByRefComponent) has a few
optimisations disabled.
2) It's easier to compile and run short console apps :)
3) Performance testing in a debugger is a really bad idea
4) Calling DynamicInvoke isn't the same as directly calling the
delegate in a strongly-typed manner

Here's the equivalent code, rewritten as a console app, including a
direct invocation, and with more iterations to give more useful
results:

using System;
using System.Diagnostics;
using System.Reflection;

class Benchmark
{
const string OpGreaterThanOrEqual = "op_GreaterThanOrEqual";

const int Iterations = 1000000;
const decimal FirstValue = 100000.00m;
const decimal SecondValue = 101000.00m;

private delegate bool OperatorTest (decimal first, decimal
second);

static void Main()
{
RunDelegateDynamic();
RunDelegateDirect();
RunReflection();
}

static void RunDelegateDirect()
{
OperatorTest d = (OperatorTest) Delegate.CreateDelegate
(typeof(OperatorTest), typeof(decimal),
OpGreaterThanOrEqual);

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
d(FirstValue, SecondValue);
}
sw.Stop();
Console.WriteLine ("Direct invoke: "+sw.ElapsedMilliseconds);
}

static void RunDelegateDynamic()
{
Delegate d = Delegate.CreateDelegate (typeof(OperatorTest),
typeof(decimal),
OpGreaterThanOrEqual);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
d.DynamicInvoke(new object[] { FirstValue, SecondValue });
}
sw.Stop();
Console.WriteLine ("Dynamic invoke: "+sw.ElapsedMilliseconds);
}

static void RunReflection()
{
MethodInfo mi =
typeof(decimal).GetMethod(OpGreaterThanOrEqual,
new Type[] {typeof(decimal), typeof(decimal) });
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
mi.Invoke(null, new object[] { FirstValue, SecondValue });
}
sw.Stop();
Console.WriteLine ("Reflection: "+sw.ElapsedMilliseconds);
}
}

Here are the results on my box, not running
Dynamic invoke: 5433
Direct invoke: 82
Reflection: 2048

So yes, calling DynamicInvoke on a delegate is still slower than using
reflection - I suspect it's using reflection under the hood, but with
some extra hoops. However, calling the delegate *directly* (which is
what you should be aiming to do normally) is much, much faster than
reflection.

Jon

Nov 12 '07 #7

P: n/a
Jon,

I got comparable results. Thank you for showing me these things. I know a
bit more about Delegates now and much more about running benchmark tests. I
appreciate your time on it.

Sincerely,
Tom Corcoran
"Jon Skeet [C# MVP]" wrote:
On Nov 12, 2:11 pm, Tom Corcoran
<TomCorco...@discussions.microsoft.comwrote:
Thanks for your reply. Here is the new code as rewritten by Nicholas. The
timing was performed within the debugger.

Four things:

1) Code within a Windows Form (or any MarshalByRefComponent) has a few
optimisations disabled.
2) It's easier to compile and run short console apps :)
3) Performance testing in a debugger is a really bad idea
4) Calling DynamicInvoke isn't the same as directly calling the
delegate in a strongly-typed manner

Here's the equivalent code, rewritten as a console app, including a
direct invocation, and with more iterations to give more useful
results:

using System;
using System.Diagnostics;
using System.Reflection;

class Benchmark
{
const string OpGreaterThanOrEqual = "op_GreaterThanOrEqual";

const int Iterations = 1000000;
const decimal FirstValue = 100000.00m;
const decimal SecondValue = 101000.00m;

private delegate bool OperatorTest (decimal first, decimal
second);

static void Main()
{
RunDelegateDynamic();
RunDelegateDirect();
RunReflection();
}

static void RunDelegateDirect()
{
OperatorTest d = (OperatorTest) Delegate.CreateDelegate
(typeof(OperatorTest), typeof(decimal),
OpGreaterThanOrEqual);

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
d(FirstValue, SecondValue);
}
sw.Stop();
Console.WriteLine ("Direct invoke: "+sw.ElapsedMilliseconds);
}

static void RunDelegateDynamic()
{
Delegate d = Delegate.CreateDelegate (typeof(OperatorTest),
typeof(decimal),
OpGreaterThanOrEqual);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
d.DynamicInvoke(new object[] { FirstValue, SecondValue });
}
sw.Stop();
Console.WriteLine ("Dynamic invoke: "+sw.ElapsedMilliseconds);
}

static void RunReflection()
{
MethodInfo mi =
typeof(decimal).GetMethod(OpGreaterThanOrEqual,
new Type[] {typeof(decimal), typeof(decimal) });
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
mi.Invoke(null, new object[] { FirstValue, SecondValue });
}
sw.Stop();
Console.WriteLine ("Reflection: "+sw.ElapsedMilliseconds);
}
}

Here are the results on my box, not running
Dynamic invoke: 5433
Direct invoke: 82
Reflection: 2048

So yes, calling DynamicInvoke on a delegate is still slower than using
reflection - I suspect it's using reflection under the hood, but with
some extra hoops. However, calling the delegate *directly* (which is
what you should be aiming to do normally) is much, much faster than
reflection.

Jon

Nov 12 '07 #8

P: n/a
Tom Corcoran <To*********@discussions.microsoft.comwrote:
I got comparable results. Thank you for showing me these things. I know a
bit more about Delegates now and much more about running benchmark tests. I
appreciate your time on it.
No problem. I'm a big fan of small console apps, because you basically
don't need any more code than what you're actually trying to run - no
messing around with buttons, events and the like :)

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 12 '07 #9

P: n/a
I've seen three ways. MethodInfo and strong type delegate make sense.
In which situation do you need dynamicInvoke

Nov 13 '07 #10

P: n/a
Creativ <Go*********@gmail.comwrote:
I've seen three ways. MethodInfo and strong type delegate make sense.
In which situation do you need dynamicInvoke
When you don't know the type of the delegate at compile-time.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Nov 13 '07 #11

P: n/a
On Nov 13, 9:15 pm, Jon Skeet [C# MVP] <sk...@pobox.comwrote:
Creativ <GongXinr...@gmail.comwrote:
I've seen three ways. MethodInfo and strong type delegate make sense.
In which situation do you need dynamicInvoke

When you don't know the type of the delegate at compile-time.

--
Jon Skeet - <sk...@pobox.com>http://www.pobox.com/~skeet Blog:http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
Can you give me an example? I don't see it. I thought
MethodInfo( reflection) will just do it and faster.

Nov 15 '07 #12

P: n/a
But MethodInfo is a different beast to a Delegate.

I'm not sure it is a good example (I would use typed On{blah} method
myself), but one /potential/ candidate for this would be a
general-purpose event invoke from EventHandlerList...

protected void OnEvent(object key, object sender, EventArgs
args) {
Delegate handler = Events[key];
if (handler != null) {
handler.DynamicInvoke(sender, args);
}
}

Other use-cases might include scenarios such as implementing
ISynchronizeInvoke:

public interface ISynchronizeInvoke {
bool InvokeRequired { get; }
IAsyncResult BeginInvoke(Delegate method, object[] args);
object EndInvoke(IAsyncResult result);
object Invoke(Delegate method, object[] args);
}

I'm not saying that they are common to write, but certainly the latter
gets /used/ very often (think System.Windows.Forms.Control)

Marc
Nov 15 '07 #13

P: n/a
On Nov 15, 8:00 am, Creativ <GongXinr...@gmail.comwrote:
I've seen three ways. MethodInfo and strong type delegate make sense.
In which situation do you need dynamicInvoke
When you don't know the type of the delegate at compile-time.

Can you give me an example? I don't see it. I thought
MethodInfo( reflection) will just do it and faster.
Consider trying to implement ISynchronizeInvoke.Invoke - you're
presented with a Delegate, and an object[]. How are you going to
execute the delegate? I suppose you *could* get the invocation list
and execute it that way, but I suspect that's basically what
DynamicInvoke does under the hood anyway.

Jon
Nov 15 '07 #14

P: n/a
Hello
I've changed some of the values used in your benchmark test(i.e: the delegate type and some of the constants) to match a more realistic situation(upon my opinion...) for the type of function we are trying to execute using invocation and i've obtained different results regarding the difference between the direct invocation and the other 2 types.

Dynamic invoke: 12976
Direct invoke: 12505
Reflection: 13332

Could someone confirm my results and suggest some reason for that?

using System;
using System.Diagnostics;
using System.Reflection;

class Benchmark
{
const string OpGreaterThanOrEqual = "op_GreaterThanOrEqual";

const int Iterations = 100000;//changed
const int V1 = 100000;
const int V2 = 100000;
const decimal FirstValue = 100000.00m;
const decimal SecondValue = 101000.00m;

private delegate bool OperatorTest(decimal first, decimal second);
private delegate void Blah(int first, int second);//added

static void Main()
{
RunDelegateDynamic();
RunDelegateDirect();
RunReflection();
Console.ReadLine();
}

//Some more time consuming function
public static void BlahTst(int first, int second)
{
int res = 0;
for (int i = 0; i < 100000; i++)
{
if (first < second)
{
res = -1;
}
else
{
res = 1;
}
}
}
static void RunDelegateDirect()
{
Blah d = (Blah)Delegate.CreateDelegate(typeof(Blah), (Type)typeof(Benchmark), "BlahTst");

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
d(V1, V2);
}
sw.Stop();
Console.WriteLine("Direct invoke: " + sw.ElapsedMilliseconds);

/*
OperatorTest d = (OperatorTest)Delegate.CreateDelegate
(typeof(OperatorTest), typeof(decimal), OpGreaterThanOrEqual);

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
d(FirstValue, SecondValue);
}
sw.Stop();
Console.WriteLine("Direct invoke: " + sw.ElapsedMilliseconds);
*/
}

static void RunDelegateDynamic()
{
Delegate d = Delegate.CreateDelegate(typeof(Blah), (Type)typeof(Benchmark), "BlahTst");
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
d.DynamicInvoke(new object[] { V1, V2 });
}
sw.Stop();
Console.WriteLine("Dynamic invoke: " + sw.ElapsedMilliseconds);

/*
Delegate d = Delegate.CreateDelegate(typeof(OperatorTest), typeof(decimal), OpGreaterThanOrEqual);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
d.DynamicInvoke(new object[] { FirstValue, SecondValue });
}
sw.Stop();
Console.WriteLine("Dynamic invoke: " + sw.ElapsedMilliseconds);
*/
}

static void RunReflection()
{
MethodInfo mi = typeof(Benchmark).GetMethod("BlahTst",
new Type[] { typeof(int), typeof(int) });
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
mi.Invoke(null, new object[] { V1, V2 });
}
sw.Stop();
Console.WriteLine("Reflection: " + sw.ElapsedMilliseconds);

/*
MethodInfo mi = typeof(decimal).GetMethod(OpGreaterThanOrEqual,
new Type[] { typeof(decimal), typeof(decimal) });
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
mi.Invoke(null, new object[] { FirstValue, SecondValue });
}
sw.Stop();
Console.WriteLine("Reflection: " + sw.ElapsedMilliseconds);
*/
}
}

Jun 27 '08 #15

P: n/a
On Apr 12, 8:38*pm, Valeriu Lacatusu wrote:
Hello
I've changed some of the values used in your benchmark test(i.e: the delegate type and some of the constants) to match a more realistic situation(uponmy opinion...) for the type of function we are trying to execute using invocation and i've obtained different results regarding the difference between the direct invocation and the other 2 types.

Dynamic invoke: 12976
Direct invoke: 12505
Reflection: 13332

Could someone confirm my results and suggest some reason for that?
Yes - the bulk of the time is now spent within the BlahTst method
itself. Calling the method dynamically doesn't make the method itself
run any slower - it just means the time taken to transfer execution
from the calling method to BlahTst is slower. When that becomes less
significant (because BlahTst is doing more work) you'll see less
difference in the results - as your numbers demonstrate.

Jon
Jun 27 '08 #16

This discussion thread is closed

Replies have been disabled for this discussion.