Delegates vs. MethodInfo When Calling Code Dynamically

G

Guest

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 ) );
}
 
N

Nicholas Paldino [.NET/C# MVP]

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]
- (e-mail address removed)

Peter Bromberg said:
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 said:
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 ) );
}
 
G

Guest

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 said:
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]
- (e-mail address removed)

Peter Bromberg said:
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 said:
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 ) );
}
 
J

Jon Skeet [C# MVP]

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
 
G

Guest

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();
}
}
}
 
J

Jon Skeet [C# MVP]

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
 
G

Guest

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 said:
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
 
J

Jon Skeet [C# MVP]

Tom Corcoran said:
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 :)
 
C

Creativ

I've seen three ways. MethodInfo and strong type delegate make sense.
In which situation do you need dynamicInvoke
 
J

Jon Skeet [C# MVP]

Creativ said:
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.
 
C

Creativ

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.
 
M

Marc Gravell

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
 
J

Jon Skeet [C# MVP]

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
 
V

Valeriu Lacatusu

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);
*/
}
}
 
J

Jon Skeet [C# MVP]

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top