简体   繁体   English

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

[英]Fastest way for Get Value of a property (Reflection) in C#

I want to know what is fastest way to get value (only for this problem) from an object`s property ? 我想知道从对象的属性中获取价值的最快方法(仅针对此问题)是什么?

after some searching I saw a post from @MarkGravell in this site 经过一番搜索,我在这个网站上看到了@MarkGravell的帖子

He wrote this code : 他写了这段代码:

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

I changed it to 我改成了

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

but I got an exception 但我得到了一个例外

 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 如果有人能以更好的方式(最快的方式)帮助我没有财产类型限制请介绍它

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). Delegate.CreateDelegate不会在这种情况下工作,因为你所得到的委托投给一些已知的类型,否则你只有DynamicInvoke这是不是比直接调用更好PropertyInfo (见这里由Marc Gravell解释)。

The most generic way I've seen which does not involve lambda expressions (like Sriram Sakthivel suggested) is shown by Jon Skeet here . Jon Skeet 在这里展示了我所见过的最通用的方法,它不涉及lambda表达式(如Sriram Sakthivel建议)。 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. 基于他的方法以及我们可以从PropertyInfo获取实际属性返回类型的事实,我们可以发明为属性调用定制的东西。

First, we define an interface: 首先,我们定义一个接口:

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

Then, an implementation of the 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);
    }
}

The InvokeGet method looks mostly like the one Jon Skeet uses. InvokeGet方法看起来与Jon Skeet使用的方法类似。

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

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. 这里,在不知道编译时确切的TResult类型的情况下,我们创建适配器并将其缓存以供后续使用,以防止将来进行大量反射调用。

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. 此外,如有必要,您可以轻松地为属性设置者扩展它。

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: 在我的机器上,当在进入循环之前从提供程序预取适配器实例时,这些是使用各种方法在循环中访问getter一千万次的结果:

  • 141 milliseconds for direct invocation 直接调用141毫秒
  • 244 milliseconds for adapter invocation 适配器调用244毫秒
  • 1800 milliseconds for reflection invocation 反射调用1800毫秒
  • 8179 milliseconds for dynamic delegate invocation 动态委托调用的时间为8179毫秒

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM