CSharp - 在 C# 中,获取属性值的最快方法( 反射)

我想知道从对象的属性中获取值的最快方法是什么?


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

但出现了一个exception


 Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.

时间:

Delegate.CreateDelegate在这种情况下不能工作,因为必须将结果委托转换为一些已知的类型,否则就不能直接调用。

首先,我们定义一个接口:


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);
 }
}

我们定义一个服务,构建和缓存提供者的一个实例,它看起来像这样:


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;
 }
}

就是这样,你可以按以下方式使用它:


PropertyCallAdapterProvider<Foo>.GetInstance("Bar").InvokeGet(fooInstance)

此外,如果有必要,可以轻松地扩展它。

在我的计算机上,使用不同的方法在循环中访问getter的结果:

  • 直接调用为141毫秒
  • 适配器调用为244毫秒
  • 反射调用需要1800毫秒
  • 动态委托调用的8179毫秒

...