我最近正在开发一个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; }
}
答案 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();
}