Skip to content

Instantly share code, notes, and snippets.

@ilmax
Created November 2, 2018 10:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ilmax/3fc9c396e984650f92b4bc801a5506a3 to your computer and use it in GitHub Desktop.
Save ilmax/3fc9c396e984650f92b4bc801a5506a3 to your computer and use it in GitHub Desktop.
Reflection vs TypeLoader
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