Skip to content

Instantly share code, notes, and snippets.

@devlead
Last active August 21, 2020 19:10
Show Gist options
  • Save devlead/0a7c4f26f0d3933d8bbe5068ca211790 to your computer and use it in GitHub Desktop.
Save devlead/0a7c4f26f0d3933d8bbe5068ca211790 to your computer and use it in GitHub Desktop.
Example .NET Core app create objects from type name

Uncached Activator vs. Cached DynamicMethod/IL

Creating objects using un cached Activator.CreateInstance

Created 3000000 in 00:00:09.9923976

Creating objects using IL/Dynamic

Created 3000000 in 00:00:00.4449962
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.3.0" />
</ItemGroup>
</Project>
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace DynamicTest
{
class Program
{
static void Main(string[] args)
{
var typeNames = Enumerable
.Repeat(new[] { "DynamicTest.Program+Customer,DynamicTest", "DynamicTest.Program+Supplier,DynamicTest", "DynamicTest.Program+Contact,DynamicTest" }, 1000000)
.SelectMany(name => name)
.ToArray();
Console.WriteLine("Creating objects using IL/Dynamic");
var sw = Stopwatch.StartNew();
foreach (var typeName in typeNames)
{
DynamicObjectActivator create = TypeConstructorCache.GetOrAdd(
typeName,
key => CreateCtor(Type.GetType(typeName))
);
var myObj = create();
switch(myObj)
{
case Customer customer:
{
// got an customer
// do stuff
}
break;
case Supplier supplier:
{
// got an supplier
// do stuff
}
break;
case Contact contact:
{
// got an contact
// do stuff
}
break;
}
}
sw.Stop();
Console.WriteLine($"Created {typeNames.Length} in {sw.Elapsed}");
Console.WriteLine("Creating objects using un cached Activator.CreateInstance");
var sw2 = Stopwatch.StartNew();
foreach (var typeName in typeNames)
{
var myObj = Activator.CreateInstance(Type.GetType(typeName)); ;
switch (myObj)
{
case Customer customer:
{
// got an customer
// do stuff
}
break;
case Supplier supplier:
{
// got an supplier
// do stuff
}
break;
case Contact contact:
{
// got an contact
// do stuff
}
break;
}
}
sw2.Stop();
Console.WriteLine($"Created {typeNames.Length} in {sw2.Elapsed}");
}
public class Customer
{ }
public class Supplier
{ }
public class Contact
{ }
public static ConcurrentDictionary<string, DynamicObjectActivator> GenericTypeConstructorCache = new ConcurrentDictionary<string, DynamicObjectActivator>();
public static ConcurrentDictionary<string, DynamicObjectActivator> TypeConstructorCache = new ConcurrentDictionary<string, DynamicObjectActivator>();
public static object StopWatch { get; private set; }
public static DynamicObjectActivator<T> CreateCtor<T>()
{
var type = typeof(T);
ConstructorInfo emptyConstructor = type.GetConstructor(Type.EmptyTypes);
var dynamicMethod = new DynamicMethod("CreateInstance", type, Type.EmptyTypes, true);
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Nop);
ilGenerator.Emit(OpCodes.Newobj, emptyConstructor);
ilGenerator.Emit(OpCodes.Ret);
return (DynamicObjectActivator<T>)dynamicMethod.CreateDelegate(typeof(DynamicObjectActivator<T>));
}
public static DynamicObjectActivator CreateCtor(Type type)
{
if (type == null)
{
throw new NullReferenceException("type");
}
ConstructorInfo emptyConstructor = type.GetConstructor(Type.EmptyTypes);
var dynamicMethod = new DynamicMethod("CreateInstance", type, Type.EmptyTypes, true);
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Nop);
ilGenerator.Emit(OpCodes.Newobj, emptyConstructor);
ilGenerator.Emit(OpCodes.Ret);
return (DynamicObjectActivator)dynamicMethod.CreateDelegate(typeof(DynamicObjectActivator));
}
public delegate T DynamicObjectActivator<T>();
public delegate object DynamicObjectActivator();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment