1
Reflection benchmarks on .NET 6 v .NET 7 v .NET 8
Date Added (UTC):
11 Apr 2024 @ 00:08
Date Updated (UTC):13 Apr 2024 @ 00:27
.NET Version(s): Tag(s):
#.Net7PerfImprovement #Reflection
Added By:
.NET Developer and tech lead from Ireland!
Benchmark Results:
Benchmark Code:
using System.Linq;
using System.Reflection;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Reports;
namespace BenchmarkDotNet.Samples
{
[Config(typeof(Config))]
[SimpleJob(RuntimeMoniker.Net60, baseline: true)]
[SimpleJob(RuntimeMoniker.Net70)]
[SimpleJob(RuntimeMoniker.Net80)]
public class ReflectionBenchmarks
{
[Benchmark]
public void MethodInvoke()
{
var instance = new Target();
var method =
typeof(Target)
.GetMethod("One",
BindingFlags.Instance |
BindingFlags.Public
);
method.Invoke(instance, parameters: null);
}
[Benchmark]
public void PrivateMethodInvoke()
{
var instance = new Target();
var method =
typeof(Target)
.GetMethod("GetSecret",
BindingFlags.Instance |
BindingFlags.NonPublic
);
var result =
method.Invoke(instance, parameters: null);
}
[Benchmark]
public void PrivateField()
{
var instance = new Target();
var field =
typeof(Target)
.GetField("secret",
BindingFlags.Instance |
BindingFlags.NonPublic
);
var value =
(string)field.GetValue(instance);
}
[Benchmark]
public void GenericMethod()
{
var instance = new Target();
var method =
typeof(Target)
.GetMethod("Generic",
BindingFlags.Instance |
BindingFlags.Public
);
var generic =
method.MakeGenericMethod(typeof(string));
var result =
generic.Invoke(instance, new[] { "David" });
}
[Benchmark]
public void AllPublicMethods()
{
var instance = new Target();
var members =
typeof(Target)
.GetMembers(
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.DeclaredOnly
)
.Where(x =>
!x.Name.StartsWith("get_") &&
!x.Name.StartsWith("set_")
)
.ToList();
}
public class Target
{
public void One()
{
var one = 1;
}
private string GetSecret() => "42";
private string secret = "42";
public string Generic<T>(T input) => $"Hello {input}!";
public void Zero() { }
public string OneA { get; set; }
public string TwoB { get; set; }
}
private class Config : ManualConfig
{
public Config()
{
SummaryStyle =
SummaryStyle.Default.WithRatioStyle(RatioStyle.Percentage);
}
}
}
}
Powered by SharpLab
// .NET 6, .NET 7, .NET 8
public void MethodInvoke()
{
Target obj = new Target();
typeof(Target).GetMethod("One", BindingFlags.Instance | BindingFlags.Public).Invoke(obj, null);
}
// .NET 6, .NET 7, .NET 8
public void PrivateMethodInvoke()
{
Target obj = new Target();
typeof(Target).GetMethod("GetSecret", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(obj, null);
}
// .NET 6, .NET 7, .NET 8
public void PrivateField()
{
Target obj = new Target();
string text = (string)typeof(Target).GetField("secret", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj);
}
// .NET 6, .NET 7, .NET 8
public void GenericMethod()
{
Target obj = new Target();
MethodInfo method = typeof(Target).GetMethod("Generic", BindingFlags.Instance | BindingFlags.Public);
Type[] array = new Type[1];
array[0] = typeof(string);
MethodInfo methodInfo = method.MakeGenericMethod(array);
string[] array2 = new string[1];
array2[0] = "David";
object[] parameters = array2;
methodInfo.Invoke(obj, parameters);
}
// .NET 6, .NET 7, .NET 8
public void AllPublicMethods()
{
new Target();
Enumerable.ToList(Enumerable.Where(typeof(Target).GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public), <> c.<> 9__4_0 ?? (<> c.<> 9__4_0 = new Func<MemberInfo, bool>(<> c.<> 9.< AllPublicMethods > b__4_0))));
}
Powered by SharpLab
// .NET 6
.method public hidebysig
instance void MethodInvoke () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 1c 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2090
// Code size 37 (0x25)
.maxstack 3
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance'
)
// sequence point: (line 31, col 13) to (line 31, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 32, col 13) to (line 37, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "One"
IL_0015: ldc.i4.s 20
IL_0017: call instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Type::GetMethod(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 39, col 13) to (line 39, col 55) in _
IL_001c: ldloc.0
IL_001d: ldnull
IL_001e: callvirt instance object [System.Runtime]System.Reflection.MethodBase::Invoke(object, object[])
IL_0023: pop
// sequence point: (line 40, col 9) to (line 40, col 10) in _
IL_0024: ret
}
// .NET 7
.method public hidebysig
instance void MethodInvoke () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 1c 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x20a0
// Code size 37 (0x25)
.maxstack 3
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance'
)
// sequence point: (line 31, col 13) to (line 31, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 32, col 13) to (line 37, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "One"
IL_0015: ldc.i4.s 20
IL_0017: call instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Type::GetMethod(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 39, col 13) to (line 39, col 55) in _
IL_001c: ldloc.0
IL_001d: ldnull
IL_001e: callvirt instance object [System.Runtime]System.Reflection.MethodBase::Invoke(object, object[])
IL_0023: pop
// sequence point: (line 40, col 9) to (line 40, col 10) in _
IL_0024: ret
}
// .NET 8
.method public hidebysig
instance void MethodInvoke () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 1c 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2050
// Code size 37 (0x25)
.maxstack 3
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance'
)
// sequence point: (line 31, col 13) to (line 31, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 32, col 13) to (line 37, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "One"
IL_0015: ldc.i4.s 20
IL_0017: call instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Type::GetMethod(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 39, col 13) to (line 39, col 55) in _
IL_001c: ldloc.0
IL_001d: ldnull
IL_001e: callvirt instance object [System.Runtime]System.Reflection.MethodBase::Invoke(object, object[])
IL_0023: pop
// sequence point: (line 40, col 9) to (line 40, col 10) in _
IL_0024: ret
}
// .NET 6
.method public hidebysig
instance void PrivateMethodInvoke () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 2a 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x20c4
// Code size 37 (0x25)
.maxstack 3
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance'
)
// sequence point: (line 45, col 13) to (line 45, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 46, col 13) to (line 51, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "GetSecret"
IL_0015: ldc.i4.s 36
IL_0017: call instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Type::GetMethod(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 53, col 13) to (line 54, col 59) in _
IL_001c: ldloc.0
IL_001d: ldnull
IL_001e: callvirt instance object [System.Runtime]System.Reflection.MethodBase::Invoke(object, object[])
IL_0023: pop
// sequence point: (line 55, col 9) to (line 55, col 10) in _
IL_0024: ret
}
// .NET 7
.method public hidebysig
instance void PrivateMethodInvoke () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 2a 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x20d4
// Code size 37 (0x25)
.maxstack 3
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance'
)
// sequence point: (line 45, col 13) to (line 45, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 46, col 13) to (line 51, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "GetSecret"
IL_0015: ldc.i4.s 36
IL_0017: call instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Type::GetMethod(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 53, col 13) to (line 54, col 59) in _
IL_001c: ldloc.0
IL_001d: ldnull
IL_001e: callvirt instance object [System.Runtime]System.Reflection.MethodBase::Invoke(object, object[])
IL_0023: pop
// sequence point: (line 55, col 9) to (line 55, col 10) in _
IL_0024: ret
}
// .NET 8
.method public hidebysig
instance void PrivateMethodInvoke () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 2a 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2084
// Code size 37 (0x25)
.maxstack 3
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance'
)
// sequence point: (line 45, col 13) to (line 45, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 46, col 13) to (line 51, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "GetSecret"
IL_0015: ldc.i4.s 36
IL_0017: call instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Type::GetMethod(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 53, col 13) to (line 54, col 59) in _
IL_001c: ldloc.0
IL_001d: ldnull
IL_001e: callvirt instance object [System.Runtime]System.Reflection.MethodBase::Invoke(object, object[])
IL_0023: pop
// sequence point: (line 55, col 9) to (line 55, col 10) in _
IL_0024: ret
}
// .NET 6
.method public hidebysig
instance void PrivateField () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 39 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x20f8
// Code size 41 (0x29)
.maxstack 3
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance'
)
// sequence point: (line 60, col 13) to (line 60, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 61, col 13) to (line 66, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "secret"
IL_0015: ldc.i4.s 36
IL_0017: callvirt instance class [System.Runtime]System.Reflection.FieldInfo [System.Runtime]System.Type::GetField(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 68, col 13) to (line 69, col 50) in _
IL_001c: ldloc.0
IL_001d: callvirt instance object [System.Runtime]System.Reflection.FieldInfo::GetValue(object)
IL_0022: castclass [System.Runtime]System.String
IL_0027: pop
// sequence point: (line 70, col 9) to (line 70, col 10) in _
IL_0028: ret
}
// .NET 7
.method public hidebysig
instance void PrivateField () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 39 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2108
// Code size 41 (0x29)
.maxstack 3
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance'
)
// sequence point: (line 60, col 13) to (line 60, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 61, col 13) to (line 66, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "secret"
IL_0015: ldc.i4.s 36
IL_0017: callvirt instance class [System.Runtime]System.Reflection.FieldInfo [System.Runtime]System.Type::GetField(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 68, col 13) to (line 69, col 50) in _
IL_001c: ldloc.0
IL_001d: callvirt instance object [System.Runtime]System.Reflection.FieldInfo::GetValue(object)
IL_0022: castclass [System.Runtime]System.String
IL_0027: pop
// sequence point: (line 70, col 9) to (line 70, col 10) in _
IL_0028: ret
}
// .NET 8
.method public hidebysig
instance void PrivateField () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 39 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x20b8
// Code size 41 (0x29)
.maxstack 3
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance'
)
// sequence point: (line 60, col 13) to (line 60, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 61, col 13) to (line 66, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "secret"
IL_0015: ldc.i4.s 36
IL_0017: callvirt instance class [System.Runtime]System.Reflection.FieldInfo [System.Runtime]System.Type::GetField(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 68, col 13) to (line 69, col 50) in _
IL_001c: ldloc.0
IL_001d: callvirt instance object [System.Runtime]System.Reflection.FieldInfo::GetValue(object)
IL_0022: castclass [System.Runtime]System.String
IL_0027: pop
// sequence point: (line 70, col 9) to (line 70, col 10) in _
IL_0028: ret
}
// .NET 6
.method public hidebysig
instance void GenericMethod () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 48 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2130
// Code size 76 (0x4c)
.maxstack 6
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance',
[1] object[]
)
// sequence point: (line 75, col 13) to (line 75, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 76, col 13) to (line 81, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "Generic"
IL_0015: ldc.i4.s 20
IL_0017: call instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Type::GetMethod(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 83, col 13) to (line 84, col 58) in _
IL_001c: ldc.i4.1
IL_001d: newarr [System.Runtime]System.Type
IL_0022: dup
IL_0023: ldc.i4.0
IL_0024: ldtoken [System.Runtime]System.String
IL_0029: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_002e: stelem.ref
IL_002f: callvirt instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Reflection.MethodInfo::MakeGenericMethod(class [System.Runtime]System.Type[])
// sequence point: (line 86, col 13) to (line 87, col 61) in _
IL_0034: ldloc.0
IL_0035: ldc.i4.1
IL_0036: newarr [System.Runtime]System.String
IL_003b: dup
IL_003c: ldc.i4.0
IL_003d: ldstr "David"
IL_0042: stelem.ref
IL_0043: stloc.1
IL_0044: ldloc.1
IL_0045: callvirt instance object [System.Runtime]System.Reflection.MethodBase::Invoke(object, object[])
IL_004a: pop
// sequence point: (line 88, col 9) to (line 88, col 10) in _
IL_004b: ret
}
// .NET 7
.method public hidebysig
instance void GenericMethod () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 48 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2140
// Code size 76 (0x4c)
.maxstack 6
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance',
[1] object[]
)
// sequence point: (line 75, col 13) to (line 75, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 76, col 13) to (line 81, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "Generic"
IL_0015: ldc.i4.s 20
IL_0017: call instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Type::GetMethod(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 83, col 13) to (line 84, col 58) in _
IL_001c: ldc.i4.1
IL_001d: newarr [System.Runtime]System.Type
IL_0022: dup
IL_0023: ldc.i4.0
IL_0024: ldtoken [System.Runtime]System.String
IL_0029: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_002e: stelem.ref
IL_002f: callvirt instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Reflection.MethodInfo::MakeGenericMethod(class [System.Runtime]System.Type[])
// sequence point: (line 86, col 13) to (line 87, col 61) in _
IL_0034: ldloc.0
IL_0035: ldc.i4.1
IL_0036: newarr [System.Runtime]System.String
IL_003b: dup
IL_003c: ldc.i4.0
IL_003d: ldstr "David"
IL_0042: stelem.ref
IL_0043: stloc.1
IL_0044: ldloc.1
IL_0045: callvirt instance object [System.Runtime]System.Reflection.MethodBase::Invoke(object, object[])
IL_004a: pop
// sequence point: (line 88, col 9) to (line 88, col 10) in _
IL_004b: ret
}
// .NET 8
.method public hidebysig
instance void GenericMethod () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 48 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x20f0
// Code size 76 (0x4c)
.maxstack 6
.locals init (
[0] class BenchmarkDotNet.Samples.ReflectionBenchmarks/Target 'instance',
[1] object[]
)
// sequence point: (line 75, col 13) to (line 75, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: stloc.0
// sequence point: (line 76, col 13) to (line 81, col 23) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldstr "Generic"
IL_0015: ldc.i4.s 20
IL_0017: call instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Type::GetMethod(string, valuetype [System.Runtime]System.Reflection.BindingFlags)
// sequence point: (line 83, col 13) to (line 84, col 58) in _
IL_001c: ldc.i4.1
IL_001d: newarr [System.Runtime]System.Type
IL_0022: dup
IL_0023: ldc.i4.0
IL_0024: ldtoken [System.Runtime]System.String
IL_0029: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_002e: stelem.ref
IL_002f: callvirt instance class [System.Runtime]System.Reflection.MethodInfo [System.Runtime]System.Reflection.MethodInfo::MakeGenericMethod(class [System.Runtime]System.Type[])
// sequence point: (line 86, col 13) to (line 87, col 61) in _
IL_0034: ldloc.0
IL_0035: ldc.i4.1
IL_0036: newarr [System.Runtime]System.String
IL_003b: dup
IL_003c: ldc.i4.0
IL_003d: ldstr "David"
IL_0042: stelem.ref
IL_0043: stloc.1
IL_0044: ldloc.1
IL_0045: callvirt instance object [System.Runtime]System.Reflection.MethodBase::Invoke(object, object[])
IL_004a: pop
// sequence point: (line 88, col 9) to (line 88, col 10) in _
IL_004b: ret
}
// .NET 6
.method public hidebysig
instance void AllPublicMethods () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 5a 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2188
// Code size 66 (0x42)
.maxstack 3
// sequence point: (line 93, col 13) to (line 93, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: pop
// sequence point: (line 94, col 13) to (line 105, col 31) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldc.i4.s 22
IL_0012: callvirt instance class [System.Runtime]System.Reflection.MemberInfo[] [System.Runtime]System.Type::GetMembers(valuetype [System.Runtime]System.Reflection.BindingFlags)
IL_0017: ldsfld class [System.Runtime]System.Func`2<class [System.Runtime]System.Reflection.MemberInfo, bool> BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<>9__4_0'
IL_001c: dup
IL_001d: brtrue.s IL_0036
IL_001f: pop
IL_0020: ldsfld class BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c' BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<>9'
IL_0025: ldftn instance bool BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<AllPublicMethods>b__4_0'(class [System.Runtime]System.Reflection.MemberInfo)
IL_002b: newobj instance void class [System.Runtime]System.Func`2<class [System.Runtime]System.Reflection.MemberInfo, bool>::.ctor(object, native int)
IL_0030: dup
IL_0031: stsfld class [System.Runtime]System.Func`2<class [System.Runtime]System.Reflection.MemberInfo, bool> BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<>9__4_0'
IL_0036: call class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0> [System.Linq]System.Linq.Enumerable::Where<class [System.Runtime]System.Reflection.MemberInfo>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Runtime]System.Func`2<!!0, bool>)
IL_003b: call class [System.Collections]System.Collections.Generic.List`1<!!0> [System.Linq]System.Linq.Enumerable::ToList<class [System.Runtime]System.Reflection.MemberInfo>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>)
IL_0040: pop
// sequence point: (line 106, col 9) to (line 106, col 10) in _
IL_0041: ret
}
// .NET 7
.method public hidebysig
instance void AllPublicMethods () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 5a 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2198
// Code size 66 (0x42)
.maxstack 3
// sequence point: (line 93, col 13) to (line 93, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: pop
// sequence point: (line 94, col 13) to (line 105, col 31) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldc.i4.s 22
IL_0012: callvirt instance class [System.Runtime]System.Reflection.MemberInfo[] [System.Runtime]System.Type::GetMembers(valuetype [System.Runtime]System.Reflection.BindingFlags)
IL_0017: ldsfld class [System.Runtime]System.Func`2<class [System.Runtime]System.Reflection.MemberInfo, bool> BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<>9__4_0'
IL_001c: dup
IL_001d: brtrue.s IL_0036
IL_001f: pop
IL_0020: ldsfld class BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c' BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<>9'
IL_0025: ldftn instance bool BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<AllPublicMethods>b__4_0'(class [System.Runtime]System.Reflection.MemberInfo)
IL_002b: newobj instance void class [System.Runtime]System.Func`2<class [System.Runtime]System.Reflection.MemberInfo, bool>::.ctor(object, native int)
IL_0030: dup
IL_0031: stsfld class [System.Runtime]System.Func`2<class [System.Runtime]System.Reflection.MemberInfo, bool> BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<>9__4_0'
IL_0036: call class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0> [System.Linq]System.Linq.Enumerable::Where<class [System.Runtime]System.Reflection.MemberInfo>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Runtime]System.Func`2<!!0, bool>)
IL_003b: call class [System.Collections]System.Collections.Generic.List`1<!!0> [System.Linq]System.Linq.Enumerable::ToList<class [System.Runtime]System.Reflection.MemberInfo>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>)
IL_0040: pop
// sequence point: (line 106, col 9) to (line 106, col 10) in _
IL_0041: ret
}
// .NET 8
.method public hidebysig
instance void AllPublicMethods () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 5a 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2148
// Code size 66 (0x42)
.maxstack 3
// sequence point: (line 93, col 13) to (line 93, col 41) in _
IL_0000: newobj instance void BenchmarkDotNet.Samples.ReflectionBenchmarks/Target::.ctor()
IL_0005: pop
// sequence point: (line 94, col 13) to (line 105, col 31) in _
IL_0006: ldtoken BenchmarkDotNet.Samples.ReflectionBenchmarks/Target
IL_000b: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle)
IL_0010: ldc.i4.s 22
IL_0012: callvirt instance class [System.Runtime]System.Reflection.MemberInfo[] [System.Runtime]System.Type::GetMembers(valuetype [System.Runtime]System.Reflection.BindingFlags)
IL_0017: ldsfld class [System.Runtime]System.Func`2<class [System.Runtime]System.Reflection.MemberInfo, bool> BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<>9__4_0'
IL_001c: dup
IL_001d: brtrue.s IL_0036
IL_001f: pop
IL_0020: ldsfld class BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c' BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<>9'
IL_0025: ldftn instance bool BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<AllPublicMethods>b__4_0'(class [System.Runtime]System.Reflection.MemberInfo)
IL_002b: newobj instance void class [System.Runtime]System.Func`2<class [System.Runtime]System.Reflection.MemberInfo, bool>::.ctor(object, native int)
IL_0030: dup
IL_0031: stsfld class [System.Runtime]System.Func`2<class [System.Runtime]System.Reflection.MemberInfo, bool> BenchmarkDotNet.Samples.ReflectionBenchmarks/'<>c'::'<>9__4_0'
IL_0036: call class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0> [System.Linq]System.Linq.Enumerable::Where<class [System.Runtime]System.Reflection.MemberInfo>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Runtime]System.Func`2<!!0, bool>)
IL_003b: call class [System.Collections]System.Collections.Generic.List`1<!!0> [System.Linq]System.Linq.Enumerable::ToList<class [System.Runtime]System.Reflection.MemberInfo>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>)
IL_0040: pop
// sequence point: (line 106, col 9) to (line 106, col 10) in _
IL_0041: ret
}
Powered by SharpLab
|
|
|
Benchmark Description:
There was some major reflection performance improvements in .NET 7, although I did see a regression when invoking private fields.
The provided benchmark code is designed to evaluate the performance of various reflection operations in .NET. Reflection is a powerful feature that allows a program to inspect and manipulate its own structure and behavior at runtime. However, reflection can be relatively slow compared to direct method calls or field access, making these benchmarks valuable for understanding the performance implications of using reflection in critical paths of an application.
### General Setup
- **.NET Versions Tested:** The benchmarks are configured to run against three different runtime versions: .NET 6.0 (as the baseline), .NET 7.0, and a hypothetical .NET 8.0. This setup allows for performance comparison across different .NET runtime versions.
- **BenchmarkDotNet:** A popular benchmarking library for .NET that provides a framework for writing and running performance tests. It is configured with a custom `Config` class that specifies the summary style to include percentage ratios, enhancing the readability of the performance differences.
- **Configuration:** The `Config` class customizes the output of the benchmark results, specifically adjusting the summary style to display ratio styles as percentages.
### Benchmark Methods
#### 1. `MethodInvoke`
- **Purpose:** Measures the performance of invoking a public instance method using reflection.
- **Importance:** This benchmark tests the overhead of dynamically invoking methods, which is common in scenarios requiring high flexibility or when interacting with APIs where the method names are not known at compile time.
- **Expected Insights:** The results will show how much slower a reflective method invocation is compared to direct calls, and how this overhead varies across different .NET versions.
#### 2. `PrivateMethodInvoke`
- **Purpose:** Evaluates the performance of invoking a private instance method using reflection.
- **Importance:** Similar to `MethodInvoke`, but focuses on non-public methods. This is crucial for testing or accessing hidden functionalities in third-party libraries or frameworks.
- **Expected Insights:** This benchmark will highlight the cost of accessing and invoking private methods reflectively, providing insights into the additional overhead, if any, compared to public method access.
#### 3. `PrivateField`
- **Purpose:** Measures the performance of accessing a private field's value using reflection.
- **Importance:** Accessing private fields is necessary in some advanced scenarios, such as serialization libraries or frameworks that need to manipulate the state of an object without exposing those fields publicly.
- **Expected Insights:** The results will indicate the overhead of reflective field access and how it compares to accessing public fields or properties.
#### 4. `GenericMethod`
- **Purpose:** Tests the performance of making a generic method call using reflection, including the overhead of constructing the generic method.
- **Importance:** Generic methods are widely used for type-safe operations. This benchmark is essential for understanding the performance implications of using reflection with generics, which adds complexity due to the need to construct the method with specific type arguments at runtime.
- **Expected Insights:** Insights into the additional overhead introduced by combining generics with reflection, which might be significant due to the dynamic type construction and method invocation.
#### 5. `AllPublicMethods`
- **Purpose:** Evaluates the performance of retrieving all public instance methods (excluding property accessors) of a class using reflection.
- **Importance:** This operation is common in scenarios where an application needs to dynamically discover available functionalities, such as plugin systems or command dispatchers.
- **Expected Insights:** This benchmark will provide an understanding of the cost associated with reflective type inspection, particularly how expensive it is to enumerate methods and filter them based on specific criteria.
### Conclusion
Running these benchmarks will offer valuable insights into the performance characteristics of reflection in .NET applications. It's important to balance the flexibility and power of reflection with its performance implications, especially in performance-critical paths. The insights gained can guide developers in making informed decisions about when and how to use reflection, or when to seek alternative approaches for achieving dynamic behavior.