在C#中获取属性值(反射)的最快方法 [英] Fastest way for Get Value of a property (Reflection) in C#

查看:78
本文介绍了在C#中获取属性值(反射)的最快方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to know what is fastest way to get value (only for this problem) from an object`s property ?

经过一番搜索之后,我看到了@MarkGravell在此站点中

after some searching I saw a post from @MarkGravell in this site

他编写了以下代码:

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

OR

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.

我不知道我的财产类型是什么它可以是任何东西如何为此目的定制代码?

I dont know what is my property type It can be anything How customize code for this purpose ?

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

If anyone can help me in better way (fastest way) without property Type restriction please introduce it

推荐答案

在这种情况下, Delegate.CreateDelegate 将不起作用,因为您必须将结果委托转换为某种已知类型,否则,您只能拥有 DynamicInvoke 并不比直接调用 PropertyInfo 好(请参阅此处由Marc Gravell解释)。

The Delegate.CreateDelegate will not work in this case, because you have to cast the resulting delegate to some known type, otherwise all you have is DynamicInvoke which is not better than direct invocation of PropertyInfo (see here explanation by Marc Gravell).

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

The most generic way I've seen which does not involve lambda expressions (like Sriram Sakthivel suggested) is shown by Jon Skeet here. Building on his approach and the fact we can get the actual property return type from PropertyInfo, we can invent something custom-tailored for properties invocation.

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

First, we define an interface:

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)使用的方法。

The InvokeGet method looks mostly like the one Jon Skeet uses.

现在,转到魔术部分。我们定义了一个服务,该服务将构建并缓存提供者的实例。看起来像这样:

Now, to the "magic" part. We define a service which will build and cache an instance of the provider. It looks like 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;
    }
}

此处,在编译时不知道确切的 TResult 类型,我们创建适配器并将其缓存以备后用,以防止将来出现大量反射调用。

Here, without knowing at compile time the exact TResult type, we create the adapter and cache it for subsequent usage in order to prevent heavy reflection calls in the future.

而已。您可以通过以下方式使用它:

That's it. You can use it in the following way:

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

此外,如有必要,您可以轻松地将此设置扩展到财产设定者。

Also, you can easily extend this for property setters if necessary.

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

On my machine those are the results for accessing the getter in loop ten million times, using various methods, when the adapter instance is pre-fetched from the provider before entering the loop:


  • 直接调用为141毫秒

  • 适配器调用为244毫秒

  • 为1800毫秒反射调用

  • 动态委托调用的8179毫秒

  • 141 milliseconds for direct invocation
  • 244 milliseconds for adapter invocation
  • 1800 milliseconds for reflection invocation
  • 8179 milliseconds for dynamic delegate invocation

这篇关于在C#中获取属性值(反射)的最快方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆