Created
November 2, 2018 10:07
-
-
Save ilmax/3fc9c396e984650f92b4bc801a5506a3 to your computer and use it in GitHub Desktop.
Reflection vs TypeLoader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Main() | |
{ | |
BenchmarkRunner.Run<TypeBenchmark>(); | |
BenchmarkRunner.Run<FieldsBenchmark>(); | |
BenchmarkRunner.Run<PropertiesBenchmark>(); | |
BenchmarkRunner.Run<MethodsBenchmark>(); | |
} | |
// Define other methods and classes here | |
[MemoryDiagnoser] | |
[MinColumn, MaxColumn] | |
[MarkdownExporterAttribute.GitHub] | |
public class TypeBenchmark : BaseReflectionTest | |
{ | |
[Benchmark(Baseline = true)] | |
public int ReflectionDiscoverAllTypes() | |
=> Reflection(); | |
[Benchmark] | |
public int TypeLoaderDiscoverAllTypes() | |
=> TypeLoader(); | |
protected override void DoSomethingUseful(ref int count, Type type) | |
{ | |
string name = type.Name; | |
string fulltypeName = type.FullName; | |
count++; | |
} | |
} | |
[MemoryDiagnoser] | |
[MinColumn, MaxColumn] | |
[MarkdownExporterAttribute.GitHub] | |
public class FieldsBenchmark : BaseReflectionTest | |
{ | |
[Benchmark(Baseline = true)] | |
public int ReflectionDiscoverAllFields() | |
=> Reflection(); | |
[Benchmark] | |
public int TypeLoaderDiscoverAllFields() | |
=> TypeLoader(); | |
protected override void DoSomethingUseful(ref int count, Type type) | |
{ | |
foreach (var property in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) | |
{ | |
string name = property.Name; | |
Type propertyType = property.FieldType; | |
count += 1; | |
} | |
count++; | |
} | |
} | |
[MemoryDiagnoser] | |
[MinColumn, MaxColumn] | |
[MarkdownExporterAttribute.GitHub] | |
public class PropertiesBenchmark : BaseReflectionTest | |
{ | |
[Benchmark(Baseline = true)] | |
public int ReflectionDiscoverAllProperties() | |
=> Reflection(); | |
[Benchmark] | |
public int TypeLoaderDiscoverAllProperties() | |
=> TypeLoader(); | |
protected override void DoSomethingUseful(ref int count, Type type) | |
{ | |
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) | |
{ | |
string name = property.Name; | |
Type propertyType = property.PropertyType; | |
count += 1; | |
} | |
count++; | |
} | |
} | |
[MemoryDiagnoser] | |
[MinColumn, MaxColumn] | |
[MarkdownExporterAttribute.GitHub] | |
public class MethodsBenchmark : BaseReflectionTest | |
{ | |
[Benchmark(Baseline = true)] | |
public int ReflectionDiscoverAllMethods() | |
=> Reflection(); | |
[Benchmark] | |
public int TypeLoaderDiscoverAllMethods() | |
=> TypeLoader(); | |
protected override void DoSomethingUseful(ref int count, Type type) | |
{ | |
foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) | |
{ | |
string methodName = method.Name; | |
Type methodType = method.ReturnType; | |
count += 1; | |
foreach (var parameter in method.GetParameters()) | |
{ | |
string paramName = parameter.Name; | |
Type paramType = parameter.ParameterType; | |
} | |
} | |
count++; | |
} | |
} | |
public abstract class BaseReflectionTest | |
{ | |
private readonly TypeLoader _tl; | |
public BaseReflectionTest() | |
{ | |
_tl = new TypeLoader("mscorlib"); | |
_tl.Resolving += | |
delegate (TypeLoader sender, AssemblyName assemblyName) | |
{ | |
string name = assemblyName.Name; | |
if (name.Equals("mscorlib", StringComparison.OrdinalIgnoreCase) || | |
name.Equals("System.Private.CoreLib", StringComparison.OrdinalIgnoreCase) || | |
name.Equals("System.Runtime", StringComparison.OrdinalIgnoreCase) || | |
name.Equals("System.Runtime.InteropServices", StringComparison.OrdinalIgnoreCase) || | |
name.Equals("netstandard", StringComparison.OrdinalIgnoreCase)) | |
{ | |
return _tl.LoadFromStream(CreateStreamForCoreAssembly()); | |
} | |
return null; | |
}; | |
} | |
private static Stream CreateStreamForCoreAssembly() | |
{ | |
// We need a core assembly in IL form. Since this version of this code is for Jitted platforms, the System.Private.Corelib | |
// of the underlying runtime will do just fine. | |
string assumedLocationOfCoreLibrary = typeof(object).Assembly.Location; | |
if (string.IsNullOrEmpty(assumedLocationOfCoreLibrary)) | |
{ | |
throw new Exception("Could not find a core assembly to use for tests as 'typeof(object).Assembly.Location` returned " + | |
"a null or empty value. The most likely cause is that you built the tests for a Jitted runtime but are running them " + | |
"on an AoT runtime."); | |
} | |
return File.OpenRead(typeof(object).Assembly.Location); | |
} | |
public Assembly ReflectionMscoreLibAssembly => typeof(Object).Assembly; | |
public Assembly TypeLoaderMscoreBuildAssembly => _tl.LoadFromStream(CreateStreamForCoreAssembly()); | |
protected int TypeLoader() | |
{ | |
int count = 0; | |
foreach (var exportedType in TypeLoaderMscoreBuildAssembly.GetExportedTypes()) | |
{ | |
count += VisitType(exportedType); | |
} | |
return count; | |
} | |
protected int Reflection() | |
{ | |
int count = 0; | |
foreach (var exportedType in ReflectionMscoreLibAssembly.GetExportedTypes()) | |
{ | |
count += VisitType(exportedType); | |
} | |
return count; | |
} | |
protected int VisitType(Type type) | |
{ | |
int count = 0; | |
if (type.BaseType != null) | |
{ | |
count += VisitType(type.BaseType); | |
} | |
var nestedTypes = type.GetNestedTypes(); | |
if (nestedTypes != null) | |
{ | |
foreach (var nestedType in nestedTypes) | |
{ | |
count += VisitType(nestedType); | |
} | |
} | |
DoSomethingUseful(ref count, type); | |
return count; | |
} | |
protected abstract void DoSomethingUseful(ref int count, Type type); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment