[英]Fastest way for Get Value of a property (Reflection) in C#
我想知道从对象的属性中获取价值的最快方法(仅针对此问题)是什么?
经过一番搜索,我在这个网站上看到了@MarkGravell的帖子
他写了这段代码:
using System;
using System.Reflection;
using System.Reflection.Emit;
public class Foo
{
public Foo(int bar)
{
Bar = bar;
}
private int Bar { get; set; }
}
static class Program {
static void Main()
{
var method = new DynamicMethod("cheat", typeof(int),
new[] { typeof(object) }, typeof(Foo), true);
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, typeof(Foo));
il.Emit(OpCodes.Callvirt, typeof(Foo).GetProperty("Bar",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
).GetGetMethod(true));
il.Emit(OpCodes.Ret);
var func = (Func<object, int>)method.CreateDelegate(
typeof(Func<object, int>));
var obj = new Foo(123);
Console.WriteLine(func(obj));
}
}
要么
var method = typeof(Foo).GetProperty("Bar",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.GetGetMethod(true);
var func = (Func<Foo, int>)
Delegate.CreateDelegate(typeof(Func<Foo, int>), method);
我改成了
var pt = propertyInfo.PropertyType; // I dont know what is Type
var method = pt.GetProperty("Bar",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.GetGetMethod(true);
var func = (Func<Foo, object>) // I dont know what is return type so set object !!!
Delegate.CreateDelegate(typeof(Func<Foo, object>), method); // I want get value as object ?!!!
return func(entity).ToString(); // cast return value to string
但我得到了一个例外
Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
我不知道我的属性类型是什么它可以是任何东西如何为此目的定制代码?
如果有人能以更好的方式(最快的方式)帮助我没有财产类型限制请介绍它
该Delegate.CreateDelegate
不会在这种情况下工作,因为你所得到的委托投给一些已知的类型,否则你只有DynamicInvoke
这是不是比直接调用更好PropertyInfo
(见这里由Marc Gravell解释)。
Jon Skeet 在这里展示了我所见过的最通用的方法,它不涉及lambda表达式(如Sriram Sakthivel建议)。 基于他的方法以及我们可以从PropertyInfo
获取实际属性返回类型的事实,我们可以发明为属性调用定制的东西。
首先,我们定义一个接口:
public interface IPropertyCallAdapter<TThis>
{
object InvokeGet(TThis @this);
//add void InvokeSet(TThis @this, object value) if necessary
}
然后,接口的实现:
public class PropertyCallAdapter<TThis, TResult> : IPropertyCallAdapter<TThis>
{
private readonly Func<TThis, TResult> _getterInvocation;
public PropertyCallAdapter(Func<TThis, TResult> getterInvocation)
{
_getterInvocation = getterInvocation;
}
public object InvokeGet(TThis @this)
{
return _getterInvocation.Invoke(@this);
}
}
InvokeGet
方法看起来与Jon Skeet使用的方法类似。
现在,到了“魔术”部分。 我们定义了一个服务,它将构建和缓存提供者的实例。 它看起来像这样:
public class PropertyCallAdapterProvider<TThis>
{
private static readonly Dictionary<string, IPropertyCallAdapter<TThis>> _instances =
new Dictionary<string,IPropertyCallAdapter<TThis>>();
public static IPropertyCallAdapter<TThis> GetInstance(string forPropertyName)
{
IPropertyCallAdapter<TThis> instance;
if (!_instances.TryGetValue(forPropertyName, out instance))
{
var property = typeof(TThis).GetProperty(
forPropertyName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo getMethod;
Delegate getterInvocation = null;
if (property != null && (getMethod = property.GetGetMethod(true)) != null)
{
var openGetterType = typeof(Func<,>);
var concreteGetterType = openGetterType
.MakeGenericType(typeof(TThis), property.PropertyType);
getterInvocation =
Delegate.CreateDelegate(concreteGetterType, null, getMethod);
}
else
{
//throw exception or create a default getterInvocation returning null
}
var openAdapterType = typeof(PropertyCallAdapter<,>);
var concreteAdapterType = openAdapterType
.MakeGenericType(typeof(TThis), property.PropertyType);
instance = Activator
.CreateInstance(concreteAdapterType, getterInvocation)
as IPropertyCallAdapter<TThis>;
_instances.Add(forPropertyName, instance);
}
return instance;
}
}
这里,在不知道编译时确切的TResult
类型的情况下,我们创建适配器并将其缓存以供后续使用,以防止将来进行大量反射调用。
而已。 您可以通过以下方式使用它:
PropertyCallAdapterProvider<Foo>.GetInstance("Bar").InvokeGet(fooInstance)
此外,如有必要,您可以轻松地为属性设置者扩展它。
在我的机器上,当在进入循环之前从提供程序预取适配器实例时,这些是使用各种方法在循环中访问getter一千万次的结果:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.