Install-Package BenchmarkDotNet;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Linq.Expressions;
using System.Reflection;
namespace ConsoleApp32
{
internal class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<PropertyAccessBenchmarks>();
}
}
public class PropertyAccessBenchmarks
{
private List<Book> booksList;
private PropertyInfo[] props;
private List<Func<Book, object>> getters;
[GlobalSetup]
public void Setup()
{
booksList = new List<Book>();
int idx = 0;
for (int i = 0; i<1000000; i++)
{
++idx;
booksList.Add(new Book()
{
Id=idx,
Name=$"Name_{idx}",
Author=$"Author_{idx}",
Abstract=$"Abstract_{idx}",
Chapter=$"Chapter_{idx}",
Title=$"Title_{idx}",
Topic=$"Topic_{idx}",
Summary=$"Summary_{idx}",
ISBN=$"ISBN_{idx}_{Guid.NewGuid().ToString("N")}"
});
}
props=typeof(Book).GetProperties();
getters=CreateGetters<Book>();
}
[Benchmark]
public int ReflectionAccess()
{
int checkSum = 0;
foreach(var bk in booksList)
{
foreach(var prop in props)
{
var val=prop.GetValue(bk);
checkSum+=val?.ToString()?.Length??0;
}
}
return checkSum;
}
[Benchmark]
public int ExpressionAccess()
{
int checkSum = 0;
foreach(var bk in booksList)
{
foreach(var get in getters)
{
var val = get(bk);
checkSum+=val?.ToString()?.Length??0;
}
}
return checkSum;
}
private static List<Func<T, object>> CreateGetters<T>()
{
var getters=new List<Func<T, object>>();
foreach(var prop in typeof(T).GetProperties())
{
var param = Expression.Parameter(typeof(T), "x");
var body = Expression.Convert(
Expression.Property(param, prop),
typeof(object));
var lambda=Expression.Lambda<Func<T,object>>(body, param);
getters.Add(lambda.Compile());
}
return getters;
}
}
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
public string Abstract { get; set; }
public string Author { get; set; }
public string Chapter { get; set; }
public string Title { get; set; }
public string Topic { get; set; }
public string Summary { get; set; }
public string ISBN { get; set; }
}
}
![image]()
BenchmarkDotNet v0.15.2, Windows 11 (10.0.26100.4946/24H2/2024Update/HudsonValley)
Unknown processor
.NET SDK 9.0.302
[Host] : .NET 8.0.18 (8.0.1825.31117), X64 RyuJIT AVX2 [AttachedDebugger]
DefaultJob : .NET 8.0.18 (8.0.1825.31117), X64 RyuJIT AVX2
| Method | Mean | Error | StdDev |
| ReflectionAccess |
79.73 ms |
1.021 ms |
0.905 ms |
| ExpressionAccess |
53.41 ms |
0.489 ms |
0.434 ms |
using System.Diagnostics;
using System.Linq.Expressions;
using System.Text;
namespace ConsoleApp31
{
internal class Program
{
static StringBuilder timeBuilder= new StringBuilder();
static void Main(string[] args)
{
var booksList = InitBooksList();
TestTimeViaReflection(booksList);
TestTimeViaExpression(booksList);
Console.WriteLine(timeBuilder.ToString());
}
static void TestTimeViaReflection(List<Book> booksList)
{
Stopwatch watch = Stopwatch.StartNew();
var props = typeof(Book).GetProperties();
StringBuilder builder = new StringBuilder(256);
foreach (var bk in booksList)
{
builder.Clear();
foreach (var prop in props)
{
builder.AppendLine($"{prop.GetValue(bk)?.ToString()??""}");
}
//Console.WriteLine(builder.ToString());
}
watch.Stop();
Console.WriteLine($"In refection cost: {watch.Elapsed.TotalSeconds} seconds");
timeBuilder.AppendLine($"In refection cost: {watch.Elapsed.TotalSeconds} seconds");
}
private static void TestTimeViaExpression(List<Book> booksList)
{
Stopwatch watch = Stopwatch.StartNew();
// Cache property getters for Book
var getters = CreateGetters<Book>();
StringBuilder builder = new StringBuilder(256);
foreach (var bk in booksList)
{
builder.Clear();
foreach (var get in getters)
{
builder.AppendLine(get(bk)?.ToString() ?? "");
}
// Writing all 1M will kill performance → just sample
//Console.WriteLine(builder.ToString());
}
watch.Stop();
Console.WriteLine($"In Expression cost {watch.Elapsed.TotalSeconds} seconds");
timeBuilder.AppendLine($"In Expression cost :{watch.Elapsed.TotalSeconds} seconds");
}
static Func<T, object>[] CreateGetters<T>()
{
return typeof(T).GetProperties()
.Select(p =>
{
var param = Expression.Parameter(typeof(T), "x");
var property = Expression.Property(param, p);
var convert = Expression.Convert(property, typeof(object));
return Expression.Lambda<Func<T, object>>(convert, param).Compile();
})
.ToArray();
}
static List<Book> InitBooksList()
{
List<Book> booksList = new List<Book>();
int idx = 0;
for (int i = 0; i<1000000; i++)
{
++idx;
booksList.Add(new Book()
{
Id=idx,
Name=$"Name_{idx}",
Author=$"Author_{idx}",
Abstract=$"Abstract_{idx}",
Chapter=$"Chapter_{idx}",
Title=$"Title_{idx}",
Topic=$"Topic_{idx}",
Summary=$"Summary_{idx}",
ISBN=$"ISBN_{idx}_{Guid.NewGuid().ToString("N")}"
});
}
return booksList;
}
}
public class Book
{
public int Id { get; set; }
public string Name { get; set; }
public string Abstract { get; set; }
public string Author { get; set; }
public string Chapter { get; set; }
public string Title { get; set; }
public string Topic { get; set; }
public string Summary { get; set; }
public string ISBN { get; set; }
}
}
![image]()