Created
January 30, 2018 13:59
-
-
Save pvginkel/fed5c8512b9dfefc2870c6853bbfbf8b to your computer and use it in GitHub Desktop.
Benchmark for creating instances of value types through compiled LINQ expressions.
This file contains 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
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Text; | |
using System.Threading.Tasks; | |
using BenchmarkDotNet.Attributes; | |
using BenchmarkDotNet.Running; | |
namespace ConsoleApp12 | |
{ | |
// The results of this benchmark on my machine are: | |
// Type | Method | Mean | Error | StdDev | | |
// ----------------------------------------------- |--------------- |----------:|----------:|----------:| | |
// ActivatorCreateInstanceBenchmark_Int64 | CreateInstance | 58.195 ns | 1.2360 ns | 1.1562 ns | | |
// ActivatorCreateInstanceBenchmark_MyLargeStruct | CreateInstance | 59.670 ns | 1.2297 ns | 1.6833 ns | | |
// ExpressionBenchmark_Int64 | CreateInstance | 4.062 ns | 0.1246 ns | 0.1105 ns | | |
// ExpressionBenchmark_MyLargeStruct | CreateInstance | 6.908 ns | 0.2018 ns | 0.2829 ns | | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var benchmarks = typeof(Program).Assembly | |
.GetTypes() | |
.Where(p => !p.IsAbstract && p.GetMethods().Any(p1 => p1.GetCustomAttributes(typeof(BenchmarkAttribute), true).Length > 0)) | |
.OrderBy(p => p.FullName) | |
.ToArray(); | |
new BenchmarkSwitcher(benchmarks).RunAllJoined(); | |
} | |
// The implementation for the benchmark below is taken from: | |
// | |
// https://stackoverflow.com/questions/325426/programmatic-equivalent-of-defaulttype/12733445#12733445 | |
// | |
public abstract class ExpressionBenchmark<T> | |
{ | |
private readonly Func<object> _factory = GetDefaultValue(typeof(T)); | |
private static Func<object> GetDefaultValue(Type type) | |
{ | |
// Validate parameters. | |
if (type == null) throw new ArgumentNullException(nameof(type)); | |
// We want an Func<object> which returns the default. | |
// Create that expression here. | |
Expression<Func<object>> e = Expression.Lambda<Func<object>>( | |
// Have to convert to object. | |
Expression.Convert( | |
// The default value, always get what the *code* tells us. | |
Expression.Default(type), typeof(object) | |
) | |
); | |
// Compile and return the value. | |
return e.Compile(); | |
} | |
[Benchmark] | |
public object CreateInstance() | |
{ | |
return _factory(); | |
} | |
} | |
public class ExpressionBenchmark_Int64 : ExpressionBenchmark<long> | |
{ | |
} | |
public class ExpressionBenchmark_MyLargeStruct : ExpressionBenchmark<MyLargeStruct> | |
{ | |
} | |
public abstract class ActivatorCreateInstanceBenchmark<T> | |
{ | |
private readonly Type _type = typeof(T); | |
[Benchmark] | |
public object CreateInstance() | |
{ | |
return Activator.CreateInstance(_type); | |
} | |
} | |
public class ActivatorCreateInstanceBenchmark_Int64 : ActivatorCreateInstanceBenchmark<long> | |
{ | |
} | |
public class ActivatorCreateInstanceBenchmark_MyLargeStruct : ActivatorCreateInstanceBenchmark<MyLargeStruct> | |
{ | |
} | |
public struct MyLargeStruct | |
{ | |
public long LongValue { get; set; } | |
public string StringValue { get; set; } | |
public int IntValue { get; set; } | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment