快速委派访问者而不使用DynamicInvoke()?

时间:2013-12-28 13:13:04

标签: c# reflection properties lambda delegates

我最近正在开发一个SQLite ORM,我遇到了一些关于动态事物的问题,(我正在编写针对C#3.5的编码)。其中之一就是如何迅速获得房产价值。我尝试了很多不同的方法,其中一个非常快(作为本机和硬编码访问几乎快)但事实是你需要使用泛型,而我只想提供类型。如果我只提供类型,我会被委托(只有慢速和绝望的DynamicInvoke方法可用)或使用MethodInfo.Invoke()......

所以我想知道当我有一个委托时,是否有任何正确的方法来获取此Invoke()(而不是DynamicInvoke)。我虽然将委托转换为Func但它不起作用。

任何技巧?

class Program
{
    static void Main(String[] args)
    {
        DummyClass dummyInstance= new DummyClass();
        dummyInstance.DummyMember = "I'm a Dummy Value!";

        Type typeDummyClass = typeof(DummyClass);

        PropertyInfo propertyInfo = typeDummyClass.GetProperty("DummyMember");
        MethodInfo methodInfo = propertyInfo.GetGetMethod();

        ParameterExpression parameterExpression = Expression.Parameter(typeDummyClass, "Instance");
        Expression expression = Expression.Property(parameterExpression, propertyInfo.Name);

        Type funcType = typeof(Func<,>);
        Type funcGenericType = funcType.MakeGenericType(typeDummyClass, propertyInfo.PropertyType);

        LambdaExpression lambdaExpression = Expression.Lambda(funcGenericType, expression, parameterExpression);
        Expression<Func<DummyClass, String>> expressionTyped = Expression.Lambda<Func<DummyClass, String>>(expression, parameterExpression);
        Delegate @delegate = lambdaExpression.Compile();
        Func<DummyClass, String> func = expressionTyped.Compile();

        TimeSpan timeSpanNativeAccess = new TimeSpan(0);
        TimeSpan timeSpanGetValueCachedAccess = new TimeSpan(0);
        TimeSpan timeSpanMethodInfoCachedAccess = new TimeSpan(0);
        TimeSpan timeSpanDelegateCachedAccess = new TimeSpan(0);
        TimeSpan timeSpanFuncCachedAccess = new TimeSpan(0);

        for (UInt32 i = 0; i < 100000; i++)
        {
            Stopwatch stopwatchNativeAccess = Stopwatch.StartNew();
            var dummyNativeAccess = dummyInstance.DummyMember;
            stopwatchNativeAccess.Stop();

            Stopwatch stopwatchGetValueCachedAccess = Stopwatch.StartNew();
            var dummyGetValueCachedAccess = propertyInfo.GetValue(dummyInstance, null);
            stopwatchGetValueCachedAccess.Stop();

            Stopwatch stopwatchMethodInfoCachedAccess = Stopwatch.StartNew();
            var dummyMethodInfoCachedAccess = methodInfo.Invoke(dummyInstance, null);
            stopwatchMethodInfoCachedAccess.Stop();

            Stopwatch stopwatchDelegateCachedAccess = Stopwatch.StartNew();
            var dummyDelegateCachedAccess = @delegate.DynamicInvoke(dummyInstance);
            stopwatchDelegateCachedAccess.Stop();

            Stopwatch stopwatchFuncCachedAccess = Stopwatch.StartNew();
            var dummyFuncCachedAccess = func.Invoke(dummyInstance); // func(dummyInstance);
            stopwatchFuncCachedAccess.Stop();

            timeSpanNativeAccess += stopwatchNativeAccess.Elapsed;
            timeSpanGetValueCachedAccess += stopwatchGetValueCachedAccess.Elapsed;
            timeSpanMethodInfoCachedAccess += stopwatchMethodInfoCachedAccess.Elapsed;
            timeSpanDelegateCachedAccess += stopwatchDelegateCachedAccess.Elapsed;
            timeSpanFuncCachedAccess += stopwatchFuncCachedAccess.Elapsed;
        }

        Console.WriteLine("timeSpanNativeAccess = " + timeSpanNativeAccess.TotalMilliseconds + " ms");
        Console.WriteLine("timeSpanGetValueCachedAccess = " + timeSpanGetValueCachedAccess.TotalMilliseconds + " ms");
        Console.WriteLine("timeSpanMethodInfoCachedAccess = " + timeSpanMethodInfoCachedAccess.TotalMilliseconds + " ms");
        Console.WriteLine("timeSpanDelegateCachedAccess = " + timeSpanDelegateCachedAccess.TotalMilliseconds + " ms");
        Console.WriteLine("timeSpanFuncCachedAccess = " + timeSpanFuncCachedAccess.TotalMilliseconds + " ms");

        Console.ReadKey();
    }
}

public class DummyClass
{
    public String DummyMember { get; set; }
}

1 个答案:

答案 0 :(得分:1)

您好我找到了一种方法来获取Invoke()方法,其中包含此处显示的代码:Faster way to cast a Func<T, T2> to Func<T, object>?

诀窍在于C#3.5不提供任何差异,因此您在创建转换时必须自己进行转换。

因此添加一个UnaryExpression来进行转换以获得Func(对于getter)

private static Func<Object, Object> GenerateAccessor(MethodInfo methodInfo)
{
    Type typeObject = typeof(Object);

    ParameterExpression @object = Expression.Parameter(typeObject, "Objet");

    UnaryExpression unaryExpression = Expression.Convert(@object, methodInfo.DeclaringType);
    MethodCallExpression methodCallExpression = Expression.Call(unaryExpression, methodInfo);
    UnaryExpression unaryExpressionBis = Expression.Convert(methodCallExpression, typeObject);

    Expression<Func<Object, Object>> epxressionFuncObjectObject = Expression.Lambda<Func<Object, Object>>(unaryExpressionBis, @object);

    return epxressionFuncObjectObject.Compile();
}