gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 02:11:02 27 4
gpt4 key购买 nike

我想知道从对象的属性中获取值(仅针对此问题)的最快方法是什么?

经过一番搜索,我在这个网站上看到了 @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

但我有一个异常(exception)

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

我不知道我的属性类型是什么,它可以是任何类型,如何为此目的自定义代码?

如果有人可以在没有属性类型限制的情况下以更好的方式(最快的方式)帮助我,请介绍一下

最佳答案

在这种情况下,Delegate.CreateDelegate 将不起作用,因为您必须将生成的委托(delegate)转换为某种已知类型,否则您所拥有的只是 DynamicInvoke,而这不是比直接调用 PropertyInfo 更好(请参阅 here Marc Gravell 的解释)。

我见过的最通用的方法不涉及 lambda 表达式(例如Sriram Sakthivel 建议)由 Jon Skeet 显示 here 。基于他的方法以及我们可以从 PropertyInfo 获取实际属性返回类型的事实,我们可以为属性调用发明一些定制的东西。

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

public interface IPropertyCallAdapter<TThis>
{
object InvokeGet(TThis @this);
//add void InvokeSet(TThis @this, object value) if necessary
}

然后,接口(interface)的实现:

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)

此外,如果需要,您可以轻松地将其扩展到属性 setter 。

在我的机器上,这些是在进入循环之前从提供者预获取适配器实例时使用各种方法在循环中访问 getter 一千万次的结果:

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

关于c# - 在 C# 中获取属性值(反射)的最快方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26731159/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com