Hi I was trying out using (cached) compiled lambda expressions for properties access, for sure I got a result much better (i.e. faster) than when using PropertyInfo.GetValue()/SetValue() method calls. However, I feel it's still really far getting close to the "native" properties speed. Is it the benchmarking method that makes the results so different from what others could get?

* <https://www.codeproject.com/Articles/584720/ExpressionplusbasedplusPropertyplusGettersplusandp>
* <http://www.palmmedia.de/Blog/2012/2/4/reflection-vs-compiled-expressions-vs-delegates-performance-comparision>
* [Compiled C# Lambda Expressions Performance](https://stackoverflow.com/questions/5568294/compiled-c-sharp-lambda-expressions-performance)

Here is below the result I got after running my piece of code below:

> 
> 
> ```
> Native: Elapsed = 00:00:00.0995876 (99.5876 ms); Step = 1.992E-005 ms
> Lambda Expression: Elapsed = 00:00:00.5369273 (536.9273 ms); Step = 1.074E-004 ms
> Property Info: Elapsed = 00:00:01.9187312 (1918.7312 ms); Step = 3.837E-004 ms
> 
> 1.000 < 5.392 < 19.267
> 
> ```
> 
> 

Honestly I feel that based on others benchmarks, the compiled lambda expressions should be twice slower than using regular properties, not like between 5 - 6 times slower.

Any thought? The bench-marking method? The way the compiled lambda expression is computed?

```
public static class Program
{
    public static void Main(params string[] args)
    {
        var stepCount = 5000000UL;

        var dummy = new Dummy();

        const string propertyName = "Soother";

        const bool propertyValue = true;

        var propertyInfo = typeof(Dummy).GetProperty(propertyName);

        var nativeBenchmark = Benchmark.Run("Native", stepCount, () => dummy.Soother = propertyValue);
        var lambdaExpressionBenchmark = Benchmark.Run("Lambda Expression", stepCount, () => dummy.Set(propertyName, propertyValue));
        var propertyInfoBenchmark = Benchmark.Run("Property Info", stepCount, () => propertyInfo.SetValue(dummy, propertyValue, null));

        var benchmarkReports = new[] { nativeBenchmark, lambdaExpressionBenchmark, propertyInfoBenchmark }.OrderBy(item => item.ElapsedMilliseconds);

        benchmarkReports.Join(Environment.NewLine).WriteLineToConsole();

        var fastest = benchmarkReports.First().ElapsedMilliseconds;

        benchmarkReports.Select(report => (report.ElapsedMilliseconds / fastest).ToString("0.000")).Join(" < ").WriteLineToConsole();

        Console.ReadKey();
    }
}

public class Dummy
{
    public bool? Soother { get; set; } = true;
}

public class BenchMarkReport
{
    #region Fields & Properties

    public string Name { get; }
    public TimeSpan ElapsedTime { get; }
    public double ElapsedMilliseconds
    {
        get
        {
            return ElapsedTime.TotalMilliseconds;
        }
    }
    public ulong StepCount { get; }
    public double StepElapsedMilliseconds
    {
        get
        {
            return ElapsedMilliseconds / StepCount;
        }
    }

    #endregion

    #region Constructors

    internal BenchMarkReport(string name, TimeSpan elapsedTime, ulong stepCount)
    {
        Name = name;
        ElapsedTime = elapsedTime;
        StepCount = stepCount;
    }

    #endregion

    #region Methods

    public override string ToString()
    {
        return $"{Name}: Elapsed = {ElapsedTime} ({ElapsedMilliseconds} ms); Step = {StepElapsedMilliseconds:0.###E+000} ms";
    }

    #endregion
}

public class Benchmark
{
    #region Fields & Properties

    private readonly Action _stepAction;

    public string Name { get; }

    public ulong StepCount { get; }

    public Benchmark(string name, ulong stepCount, Action stepAction)
    {
        Name = name;
        StepCount = stepCount;
        _stepAction = stepAction;
    }

    #endregion

    #region Constructors

    #endregion

    #region Methods

    public static BenchMarkReport Run(string name, ulong stepCount, Action stepAction)
    {
        var benchmark = new Benchmark(name, stepCount, stepAction);

        var benchmarkReport = benchmark.Run();

        return benchmarkReport;
    }

    public BenchMarkReport Run()
    {
        return Run(StepCount);
    }

    public BenchMarkReport Run(ulong stepCountOverride)
    {
        var stopwatch = Stopwatch.StartNew();

        for (ulong i = 0; i < StepCount; i++)
        {
            _stepAction();
        }

        stopwatch.Stop();

        var benchmarkReport = new BenchMarkReport(Name, stopwatch.Elapsed, stepCountOverride);

        return benchmarkReport;
    }

    #endregion
}

public static class ObjectExtensions
{
    public static void WriteToConsole<TInstance>(this TInstance instance)
    {
        Console.Write(instance);
    }

    public static void WriteLineToConsole<TInstance>(this TInstance instance)
    {
        Console.WriteLine(instance);
    }

    // Goodies: add name inference from property lambda expression
    // e.g. "instance => instance.PropertyName" redirected using "PropertyName"

    public static TProperty Get<TInstance, TProperty>(this TInstance instance, string propertyName)
    {
        return FastPropertyRepository<TInstance, TProperty>.GetGetter(propertyName)(instance);
    }

    public static void Set<TInstance, TProperty>(this TInstance instance, string propertyName, TProperty propertyValue)
    {
        FastPropertyRepository<TInstance, TProperty>.GetSetter(propertyName)(instance, propertyValue);
    }
}

public static class EnumerableExtensions
{
    public static string Join<TSource>(this IEnumerable<TSource> source, string separator = ", ")
    {
        return string.Join(separator, source);
    }
}

internal static class FastPropertyRepository<TInstance, TProperty>
{
    private static readonly IDictionary<string, Action<TInstance, TProperty>> Setters;
    private static readonly IDictionary<string, Func<TInstance, TProperty>> Getters;

    static FastPropertyRepository()
    {
        Getters = new ConcurrentDictionary<string, Func<TInstance, TProperty>>();
        Setters = new ConcurrentDictionary<string, Action<TInstance, TProperty>>();
    }

    public static Func<TInstance, TProperty> GetGetter(string propertyName)
    {
        Func<TInstance, TProperty> getter;
        if (!Getters.TryGetValue(propertyName, out getter))
        {
            getter = FastPropertyFactory.GeneratePropertyGetter<TInstance, TProperty>(propertyName);
            Getters[propertyName] = getter;
        }

        return getter;
    }

    public static Action<TInstance, TProperty> GetSetter(string propertyName)
    {
        Action<TInstance, TProperty> setter;
        if (!Setters.TryGetValue(propertyName, out setter))
        {
            setter = FastPropertyFactory.GeneratePropertySetter<TInstance, TProperty>(propertyName);
            Setters[propertyName] = setter;
        }

        return setter;
    }
}

internal static class FastPropertyFactory
{
    public static Func<TInstance, TProperty> GeneratePropertyGetter<TInstance, TProperty>(string propertyName)
    {
        var parameterExpression = Expression.Parameter(typeof(TInstance), "value");

        var propertyValueExpression = Expression.Property(parameterExpression, propertyName);

        var expression = propertyValueExpression.Type == typeof(TProperty) ? propertyValueExpression : (Expression)Expression.Convert(propertyValueExpression, typeof(TProperty));

        var propertyGetter = Expression.Lambda<Func<TInstance, TProperty>>(expression, parameterExpression).Compile();

        return propertyGetter;
    }

    public static Action<TInstance, TProperty> GeneratePropertySetter<TInstance, TProperty>(string propertyName)
    {
        var instanceParameterExpression = Expression.Parameter(typeof(TInstance));

        var parameterExpression = Expression.Parameter(typeof(TProperty), propertyName);

        var propertyValueExpression = Expression.Property(instanceParameterExpression, propertyName);

        var conversionExpression = propertyValueExpression.Type == typeof(TProperty) ? parameterExpression : (Expression)Expression.Convert(parameterExpression, propertyValueExpression.Type);

        var propertySetter = Expression.Lambda<Action<TInstance, TProperty>>(Expression.Assign(propertyValueExpression, conversionExpression), instanceParameterExpression, parameterExpression).Compile();

        return propertySetter;
    }
}

```