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
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).
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
}
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.
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.
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With