1 Star 0 Fork 0

deu2019/pzf

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
ReflectionHelper.cs 37.50 KB
一键复制 编辑 原始数据 按行查看 历史
deu2019 提交于 2020-06-09 22:44 . commit
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections.Generic;
using Pfz.Threading;
using Pfz.Extensions;
using Pfz.DataTypes;
namespace Pfz
{
/// <summary>
/// This class allows you to get members from types more safely than using
/// string literals. It only exists because C# does not have fieldinfoof,
/// propertyinfoof and methodinfoof.
/// </summary>
public static class ReflectionHelper
{
#region GetMember
/// <summary>
/// Gets a member by it's expression usage.
/// For example, GetMember(() => obj.GetType()) will return the
/// GetType method.
/// </summary>
public static MemberInfo GetMember<T>(Expression<Func<T>> expression)
{
if (expression == null)
throw new ArgumentNullException("expression");
var body = expression.Body;
switch(body.NodeType)
{
case ExpressionType.MemberAccess:
MemberExpression memberExpression = (MemberExpression)body;
return memberExpression.Member;
case ExpressionType.Call:
MethodCallExpression callExpression = (MethodCallExpression)body;
return callExpression.Method;
case ExpressionType.New:
NewExpression newExpression = (NewExpression)body;
return newExpression.Constructor;
}
throw new ArgumentException("expression.Body must be a member or call expression.", "expression");
}
#endregion
#region GetConstructor
/// <summary>
/// Gets the constructor info from a sample construction call expression.
/// Example: GetConstructor(() => new Control()) will return the constructor
/// info for the default constructor of Control.
/// </summary>
public static ConstructorInfo GetConstructor<T>(Expression<Func<T>> expression)
{
return (ConstructorInfo)GetMember(expression);
}
#endregion
#region GetField
/// <summary>
/// Gets a field from a sample usage.
/// Example: GetField(() => Type.EmptyTypes) will return the FieldInfo of
/// EmptyTypes.
/// </summary>
public static FieldInfo GetField<T>(Expression<Func<T>> expression)
{
return (FieldInfo)GetMember(expression);
}
#endregion
#region GetProperty
/// <summary>
/// Gets a property from a sample usage.
/// Example: GetProperty(() => str.Length) will return the property info
/// of Length.
/// </summary>
public static PropertyInfo GetProperty<T>(Expression<Func<T>> expression)
{
return (PropertyInfo)GetMember(expression);
}
#endregion
#region GetMethod
/// <summary>
/// Gets a method info of a void method.
/// Example: GetMethod(() => Console.WriteLine("")); will return the
/// MethodInfo of WriteLine that receives a single argument.
/// </summary>
public static MethodInfo GetMethod(Expression<Action> expression)
{
if (expression == null)
throw new ArgumentNullException("expression");
var body = expression.Body;
if (body.NodeType != ExpressionType.Call)
throw new ArgumentException("expression.Body must be a Call expression.", "expression");
MethodCallExpression callExpression = (MethodCallExpression)body;
return callExpression.Method;
}
/// <summary>
/// Gets the MethodInfo of a method that returns a value.
/// Example: GetMethod(() => Console.ReadLine()); will return the method info
/// of ReadLine.
/// </summary>
public static MethodInfo GetMethod<T>(Expression<Func<T>> expression)
{
return (MethodInfo)GetMember(expression);
}
#endregion
#region GetDefaultConstructorDelegate
private static YieldReaderWriterLockSlim _defaultConstructorsLock;
private static readonly Dictionary<Type, Func<object>> _defaultConstructorsDictionary = new Dictionary<Type, Func<object>>();
private static readonly Func<Type, Func<object>> _getDefaultConstructorDelegate = GetDefaultConstructorDelegate<object>;
/// <summary>
/// Gets a function that creates objects of the given type.
/// The object must have a default constructor.
/// </summary>
public static Func<object> GetDefaultConstructorDelegate(Type objectType)
{
var result = _defaultConstructorsDictionary.GetOrCreateValue(ref _defaultConstructorsLock, objectType, _getDefaultConstructorDelegate);
return result;
}
private static YieldReaderWriterLockSlim _typedDefaultConstructorsLock;
private static readonly Dictionary<KeyValuePair<Type, Type>, Delegate> _typedDefaultConstructorsDictionary = new Dictionary<KeyValuePair<Type, Type>, Delegate>();
private static readonly Func<KeyValuePair<Type, Type>, Delegate> _getTypedDefaultConstructorDelegate = _GetDefaultConstructorDelegate;
/// <summary>
/// Gets the default constructor for the given objectType, but return
/// it already casted to a given "T".
/// </summary>
public static Func<T> GetDefaultConstructorDelegate<T>(Type objectType)
{
if (objectType == null)
throw new ArgumentNullException("objectType");
var pair = Pair.Create(typeof(Func<T>), objectType);
var result = _typedDefaultConstructorsDictionary.GetOrCreateValue(ref _typedDefaultConstructorsLock, pair, _getTypedDefaultConstructorDelegate);
return (Func<T>)result;
}
private static Delegate _GetDefaultConstructorDelegate(KeyValuePair<Type, Type> pair)
{
var funcType = pair.Key;
var objectType = pair.Value;
var resultType = funcType.GetGenericArguments()[0];
Expression expression = Expression.New(objectType);
if
(
resultType != objectType &&
(
objectType.IsValueType ||
!resultType.IsAssignableFrom(objectType)
)
)
{
expression = Expression.Convert(expression, resultType);
}
var lambdaExpression = Expression.Lambda(funcType, expression);
var func = lambdaExpression.Compile();
return func;
}
#endregion
#region GetConstructorDelegate<T>
/// <summary>
/// Creates a delegate (of type T) for the given constructor.
/// The delegate type should match the number of parameters in the constructor.
/// Casts are done if required but no other conversions are done.
/// </summary>
public static T GetConstructorDelegate<T>(ConstructorInfo constructor)
{
object result = GetConstructorDelegate(constructor, typeof(T));
return (T)result;
}
private static YieldReaderWriterLockSlim _getTypedConstructorLock;
private static readonly Dictionary<KeyValuePair<ConstructorInfo, Type>, Delegate> _typedConstructors = new Dictionary<KeyValuePair<ConstructorInfo, Type>, Delegate>();
private static readonly Func<KeyValuePair<ConstructorInfo, Type>, Delegate> _getTypedConstructorDelegate = _GetConstructorDelegate;
/// <summary>
/// Creates a delegate for the given constructor.
/// The delegate type should match the number of parameters in the constructor.
/// Casts are done if required but no other conversions are done.
/// </summary>
public static Delegate GetConstructorDelegate(ConstructorInfo constructor, Type delegateType)
{
if (constructor == null)
throw new ArgumentNullException("constructor");
if (!delegateType.IsSubclassOf(typeof(Delegate)))
throw new ArgumentException("delegateType is not a Delegate.", "delegateType");
var pair = Pair.Create(constructor, delegateType);
var result = _typedConstructors.GetOrCreateValue(ref _getTypedConstructorLock, pair, _getTypedConstructorDelegate);
return result;
}
private static Delegate _GetConstructorDelegate(KeyValuePair<ConstructorInfo, Type> pair)
{
var constructor = pair.Key;
var delegateType = pair.Value;
var invokeMethod = delegateType.GetMethod("Invoke");
if (invokeMethod == null)
throw new InvalidOperationException("The given delegate type does not have an Invoke method. Is this a compilation error?");
var constructorType = constructor.DeclaringType;
var invokeReturnType = invokeMethod.ReturnType;
bool isInvokeVoid = invokeReturnType == typeof(void);
if (isInvokeVoid)
throw new InvalidOperationException("The return type the delegate is incompatible.");
var invokeParameterTypes = invokeMethod.GetParameterTypes();
var constructorParameterTypes = constructor.GetParameterTypes();
int count = invokeParameterTypes.Length;
if (constructorParameterTypes.Length != count)
throw new InvalidOperationException("The number of parameters between the constructor and the delegate is not compatible.");
var parameterExpressions = new ParameterExpression[count];
var arguments = new Expression[count];
for(int i=0; i<count; i++)
{
var argument = _GetArgumentExpression(i, constructorParameterTypes, invokeParameterTypes, parameterExpressions);
arguments[i] = argument;
}
Expression resultExpression = Expression.New(constructor, arguments);
if (constructorType != invokeReturnType)
resultExpression = Expression.Convert(resultExpression, invokeReturnType);
var lambda = Expression.Lambda(delegateType, resultExpression, parameterExpressions);
var compiled = lambda.Compile();
return compiled;
}
#endregion
#if !WINDOWS_PHONE
#region GetConstructorDelegate
private static YieldReaderWriterLockSlim _constructorsLock;
private static readonly Dictionary<ConstructorInfo, FastDynamicDelegate> _constructors = new Dictionary<ConstructorInfo, FastDynamicDelegate>();
private static readonly Func<ConstructorInfo, FastDynamicDelegate> _getConstructorDelegate = _CreateConstructorDelegate;
/// <summary>
/// Gets a constructor invoker delegate for the given constructor info.
/// Using the delegate is much faster than calling the Invoke method on the constructor,
/// but if you invoke it only once, it will do no good as some time is spent compiling
/// such delegate.
/// </summary>
public static FastDynamicDelegate GetConstructorDelegate(ConstructorInfo constructor)
{
if (constructor == null)
throw new ArgumentNullException("constructor");
var result = _constructors.GetOrCreateValue(ref _constructorsLock, constructor, _getConstructorDelegate);
return result;
}
private static FastDynamicDelegate _CreateConstructorDelegate(ConstructorInfo constructor)
{
var parametersExpression = Expression.Parameter(typeof(object[]), "parameters");
var variables = new List<ParameterExpression>();
var beforeInstructions = new List<Expression>();
var afterInstructions = new List<Expression>();
Expression[] arrayAccesses = null;
var parameters = constructor.GetParameters();
int count = parameters.Length;
if (count != 0)
{
arrayAccesses = new Expression[count];
for (int i = 0; i < count; i++)
{
var parameter = parameters[i];
var parameterType = parameter.ParameterType;
var constantExpression = Expression.Constant(i);
Expression accessParameterExpression = Expression.ArrayAccess(parametersExpression, constantExpression);
if (parameterType.IsByRef)
{
parameterType = parameterType.GetElementType();
if (parameterType != typeof(object))
{
var variable = Expression.Variable(parameterType);
variables.Add(variable);
arrayAccesses[i] = variable;
if (!parameter.IsOut)
{
var effectiveAccessParameterExpression = accessParameterExpression;
if (parameterType != typeof(object))
effectiveAccessParameterExpression = Expression.Convert(accessParameterExpression, parameterType);
var setIn = Expression.Assign(variable, effectiveAccessParameterExpression);
beforeInstructions.Add(setIn);
}
Expression accessVariable = variable;
if (parameterType != typeof(object))
accessVariable = Expression.Convert(variable, typeof(object));
var setOut = Expression.Assign(accessParameterExpression, accessVariable);
afterInstructions.Add(setOut);
continue;
}
}
if (parameterType != typeof(object))
accessParameterExpression = Expression.Convert(accessParameterExpression, parameterType);
arrayAccesses[i] = accessParameterExpression;
}
}
var newExpression = Expression.New(constructor, arrayAccesses);
var returnTarget = Expression.Label(typeof(object));
var instructions = new List<Expression>();
instructions.AddRange(beforeInstructions);
ParameterExpression resultVariable = null;
Expression body = newExpression;
if (constructor.DeclaringType != typeof(object))
body = Expression.Convert(newExpression, typeof(object));
resultVariable = Expression.Variable(typeof(object));
variables.Add(resultVariable);
body = Expression.Assign(resultVariable, body);
instructions.Add(body);
instructions.AddRange(afterInstructions);
var returnExpression = Expression.Return(returnTarget, resultVariable);
instructions.Add(returnExpression);
instructions.Add(Expression.Label(returnTarget, Expression.Constant(null, typeof(object))));
body = Expression.Block(typeof(object), variables, instructions);
var result = Expression.Lambda<FastDynamicDelegate>(body, parametersExpression);
return result.Compile();
}
#endregion
#region GetMethodCallDelegate
private static YieldReaderWriterLockSlim _methodsLock;
private static readonly Dictionary<MethodInfo, FastMethodCallDelegate> _methodsDictionary = new Dictionary<MethodInfo, FastMethodCallDelegate>();
/// <summary>
/// Gets a delegate to call the given method in a fast manner.
/// </summary>
public static FastMethodCallDelegate GetMethodCallDelegate(MethodInfo method)
{
var result = _methodsDictionary.GetOrCreateValue(ref _methodsLock, method, _CreateMethodCallDelegate);
return result;
}
private static FastMethodCallDelegate _CreateMethodCallDelegate(MethodInfo method)
{
var parametersExpression = Expression.Parameter(typeof(object[]));
ParameterExpression targetExpression = Expression.Parameter(typeof(object));
Expression castTarget = null;
if (!method.IsStatic)
{
castTarget = targetExpression;
if (method.ReturnType != typeof(object))
castTarget = Expression.Convert(targetExpression, method.DeclaringType);
}
var variables = new List<ParameterExpression>();
var beforeInstructions = new List<Expression>();
var afterInstructions = new List<Expression>();
Expression[] arrayAccesses = null;
var parameters = method.GetParameters();
int count = parameters.Length;
if (count != 0)
{
arrayAccesses = new Expression[count];
for (int i = 0; i < count; i++)
{
var parameter = parameters[i];
var parameterType = parameter.ParameterType;
var constantExpression = Expression.Constant(i);
Expression accessParameterExpression = Expression.ArrayAccess(parametersExpression, constantExpression);
if (parameterType.IsByRef)
{
parameterType = parameterType.GetElementType();
if (parameterType != typeof(object))
{
var variable = Expression.Variable(parameterType);
variables.Add(variable);
arrayAccesses[i] = variable;
if (!parameter.IsOut)
{
var effectiveAccessParameterExpression = accessParameterExpression;
if (parameterType != typeof(object))
effectiveAccessParameterExpression = Expression.Convert(accessParameterExpression, parameterType);
var setIn = Expression.Assign(variable, effectiveAccessParameterExpression);
beforeInstructions.Add(setIn);
}
Expression accessVariable = variable;
if (parameterType != typeof(object))
accessVariable = Expression.Convert(variable, typeof(object));
var setOut = Expression.Assign(accessParameterExpression, accessVariable);
afterInstructions.Add(setOut);
continue;
}
}
if (parameterType != typeof(object))
accessParameterExpression = Expression.Convert(accessParameterExpression, parameterType);
arrayAccesses[i] = accessParameterExpression;
}
}
MethodCallExpression callExpression;
if (method.IsStatic)
callExpression = Expression.Call(method, arrayAccesses);
else
callExpression = Expression.Call(castTarget, method, arrayAccesses);
var returnTarget = Expression.Label(typeof(object));
var instructions = new List<Expression>();
instructions.AddRange(beforeInstructions);
ParameterExpression resultVariable = null;
Expression body = callExpression;
if (method.ReturnType != typeof(void))
{
if (method.ReturnType != typeof(object))
body = Expression.Convert(callExpression, typeof(object));
resultVariable = Expression.Variable(typeof(object));
variables.Add(resultVariable);
body = Expression.Assign(resultVariable, body);
}
instructions.Add(body);
instructions.AddRange(afterInstructions);
if (method.ReturnType == typeof(void))
{
var returnExpression = Expression.Return(returnTarget, Expression.Constant(null, typeof(object)), typeof(object));
instructions.Add(returnExpression);
}
else
{
var returnExpression = Expression.Return(returnTarget, resultVariable);
instructions.Add(returnExpression);
}
instructions.Add(Expression.Label(returnTarget, Expression.Constant(null, typeof(object))));
body = Expression.Block(typeof(object), variables, instructions);
var result = Expression.Lambda<FastMethodCallDelegate>(body, targetExpression, parametersExpression);
return result.Compile();
}
#endregion
#endif
#region GetMethodCallDelegate<T>
/// <summary>
/// Creates a method call delegate for the given method info.
/// The delegateType (T) should have the same amount of parameters as the method. Note
/// that non-static methods have a first parameter to represent the instance.
/// </summary>
public static T GetMethodCallDelegate<T>(MethodInfo method)
{
object result = GetMethodCallDelegate(method, typeof(T));
return (T)result;
}
private static YieldReaderWriterLockSlim _getTypedMethodCallLock;
private static readonly Dictionary<KeyValuePair<MethodInfo, Type>, Delegate> _getTypedMethodCallDictionary = new Dictionary<KeyValuePair<MethodInfo, Type>, Delegate>();
private static readonly Func<KeyValuePair<MethodInfo, Type>, Delegate> _getTypedMethodCallDelegate = _GetTypedMethodCallDelegate;
/// <summary>
/// Creates a method call delegate for the given method info.
/// The delegateType should have the same amount of parameters as the method. Note
/// that non-static methods have a first parameter to represent the instance.
/// </summary>
public static Delegate GetMethodCallDelegate(MethodInfo method, Type delegateType)
{
if (method == null)
throw new ArgumentNullException("method");
if (!delegateType.IsSubclassOf(typeof(Delegate)))
throw new ArgumentException("delegateType is not a Delegate.", "delegateType");
var pair = Pair.Create(method, delegateType);
var result = _getTypedMethodCallDictionary.GetOrCreateValue(ref _getTypedMethodCallLock, pair, _getTypedMethodCallDelegate);
return result;
}
private static Delegate _GetTypedMethodCallDelegate(KeyValuePair<MethodInfo, Type> pair)
{
var method = pair.Key;
var delegateType = pair.Value;
var invokeMethod = delegateType.GetMethod("Invoke");
if (invokeMethod == null)
throw new InvalidOperationException("The given delegate type does not have an Invoke method. Is this a compilation error?");
var methodReturnType = method.ReturnType;
var invokeReturnType = invokeMethod.ReturnType;
bool isMethodVoid = methodReturnType == typeof(void);
bool isInvokeVoid = invokeReturnType == typeof(void);
if (isMethodVoid != isInvokeVoid)
throw new InvalidOperationException("The return type of the method and the delegate is incompatible.");
var invokeParameterTypes = invokeMethod.GetParameterTypes();
var methodParameterTypes = new List<Type>();
if (!method.IsStatic)
methodParameterTypes.Add(method.DeclaringType);
methodParameterTypes.AddRange(method.GetParameterTypes());
int count = invokeParameterTypes.Length;
if (methodParameterTypes.Count != count)
throw new InvalidOperationException("The number of parameters between the method and the delegate is not compatible. Note that non-static methods have the additional \"this\" parameter as the first one.");
var parameterExpressions = new ParameterExpression[count];
int startIndex = 0;
int argumentCount = count;
if (!method.IsStatic)
{
startIndex = 1;
argumentCount--;
}
var arguments = new Expression[argumentCount];
for(int i=0; i<argumentCount; i++)
{
var argument = _GetArgumentExpression(i+startIndex, methodParameterTypes, invokeParameterTypes, parameterExpressions);
arguments[i] = argument;
}
MethodCallExpression callExpression;
if (method.IsStatic)
callExpression = Expression.Call(method, arguments);
else
{
var instanceExpression = _GetArgumentExpression(0, methodParameterTypes, invokeParameterTypes, parameterExpressions);
callExpression = Expression.Call(instanceExpression, method, arguments);
}
Expression resultExpression = callExpression;
if (methodReturnType != invokeReturnType)
resultExpression = Expression.Convert(resultExpression, invokeReturnType);
var lambda = Expression.Lambda(delegateType, resultExpression, parameterExpressions);
var compiled = lambda.Compile();
return compiled;
}
private static Expression _GetArgumentExpression(int index, IList<Type> methodParameterTypes, Type[] invokeParameterTypes, ParameterExpression[] parameterExpressions)
{
var invokeParameterType = invokeParameterTypes[index];
var methodParameterType = methodParameterTypes[index];
var parameter = Expression.Parameter(invokeParameterType, "P" + index);
parameterExpressions[index] = parameter;
if (methodParameterType == invokeParameterType)
return parameter;
var convert = Expression.Convert(parameter, methodParameterType);
return convert;
}
#endregion
#region GetPropertyGetterDelegate
private static YieldReaderWriterLockSlim _getPropertyLock;
private static readonly Dictionary<PropertyInfo, Func<object, object>> _getPropertiesDictionary = new Dictionary<PropertyInfo,Func<object, object>>();
private static readonly Func<PropertyInfo, Func<object, object>> _getPropertyGetterDelegate = GetPropertyGetterDelegate<object, object>;
/// <summary>
/// Gets a delegate to read values from the given property in a very fast manner.
/// </summary>
public static Func<object, object> GetPropertyGetterDelegate(PropertyInfo property)
{
var result = _getPropertiesDictionary.GetOrCreateValue(ref _getPropertyLock, property, _getPropertyGetterDelegate);
return result;
}
private static YieldReaderWriterLockSlim _getTypedPropertyLock;
private static readonly Dictionary<KeyValuePair<Type, PropertyInfo>, Delegate> _getTypedPropertiesDictionary = new Dictionary<KeyValuePair<Type, PropertyInfo>, Delegate>();
private static readonly Func<KeyValuePair<Type, PropertyInfo>, Delegate> _getTypedPropertyGetterDelegate = _GetPropertyGetterDelegate;
/// <summary>
/// Gets a delegate to read values from the given property in a very fast manner.
/// The result will be already cast or will even avoid casts if the
/// generic types are correct.
/// </summary>
public static Func<TInstance, TOutput> GetPropertyGetterDelegate<TInstance, TOutput>(PropertyInfo property)
{
if (property == null)
throw new ArgumentNullException("property");
var pair = Pair.Create(typeof(Func<TInstance, TOutput>), property);
var result = _getTypedPropertiesDictionary.GetOrCreateValue(ref _getTypedPropertyLock, pair, _getTypedPropertyGetterDelegate);
return (Func<TInstance, TOutput>)result;
}
private static Delegate _GetPropertyGetterDelegate(KeyValuePair<Type, PropertyInfo> pair)
{
var funcType = pair.Key;
var property = pair.Value;
var funcArguments = funcType.GetGenericArguments();
var instanceType = funcArguments[0];
var resultType = funcArguments[1];
var parameter = Expression.Parameter(instanceType, "instance");
Expression resultExpression;
var getMethod = property.GetGetMethod();
if (getMethod == null)
throw new ArgumentException("Property " + property.Name + " can't be read.", "read");
if (getMethod.IsStatic)
resultExpression = Expression.MakeMemberAccess(null, property);
else
{
Expression readParameter = parameter;
if (property.DeclaringType != instanceType)
readParameter = Expression.Convert(parameter, property.DeclaringType);
resultExpression = Expression.MakeMemberAccess(readParameter, property);
}
if (property.PropertyType != resultType)
resultExpression = Expression.Convert(resultExpression, resultType);
var lambda = Expression.Lambda(funcType, resultExpression, parameter);
var result = lambda.Compile();
return result;
}
#endregion
#region GetPropertySetterDelegate
private static YieldReaderWriterLockSlim _setPropertyLock;
private static readonly Dictionary<PropertyInfo, Action<object, object>> _setPropertiesDictionary = new Dictionary<PropertyInfo, Action<object, object>>();
private static readonly Func<PropertyInfo, Action<object, object>> _getPropertySetterDelegate = GetPropertySetterDelegate<object, object>;
/// <summary>
/// Gets a delegate that can be used to do very fast sets on the given property.
/// </summary>
public static Action<object, object> GetPropertySetterDelegate(PropertyInfo property)
{
var result = _setPropertiesDictionary.GetOrCreateValue(ref _setPropertyLock, property, _getPropertySetterDelegate);
return result;
}
private static YieldReaderWriterLockSlim _typedPropertySetterDelegatesLock;
private static readonly Dictionary<KeyValuePair<Type, PropertyInfo>, Delegate> _typedPropertySetterDelegatesDictionary = new Dictionary<KeyValuePair<Type, PropertyInfo>, Delegate>();
private static Func<KeyValuePair<Type, PropertyInfo>, Delegate> _typedGetPropertySetterDelegate = _TypedGetPropertySetterDelegate;
/// <summary>
/// Gets a delegate that can be used to do very fast sets on the given property.
/// If the generic types are correct, casts can be avoided to improve performance
/// even further.
/// </summary>
public static Action<TInstance, TValue> GetPropertySetterDelegate<TInstance, TValue>(PropertyInfo property)
{
if (property == null)
throw new ArgumentNullException("property");
var pair = Pair.Create(typeof(Action<TInstance, TValue>), property);
var result = _typedPropertySetterDelegatesDictionary.GetOrCreateValue(ref _typedPropertySetterDelegatesLock, pair, _typedGetPropertySetterDelegate);
return (Action<TInstance, TValue>)result;
}
private static Delegate _TypedGetPropertySetterDelegate(KeyValuePair<Type, PropertyInfo> pair)
{
var actionType = pair.Key;
var property = pair.Value;
var actionArguments = actionType.GetGenericArguments();
var instanceType = actionArguments[0];
var valueType = actionArguments[1];
var instanceParameter = Expression.Parameter(instanceType, "instance");
var valueParameter = Expression.Parameter(valueType, "value");
Expression readValueParameter = valueParameter;
if (property.PropertyType != valueType)
readValueParameter = Expression.Convert(valueParameter, property.PropertyType);
// .Net 3.5 does not have assign
// but we can call the set method directly (and we need it to test for static).
var setMethod = property.GetSetMethod(true);
if (setMethod == null)
throw new ArgumentException("Property " + property.Name + " is read-only.", "property");
Expression setExpression;
if (setMethod.IsStatic)
setExpression = Expression.Call(setMethod, readValueParameter);
else
{
Expression readInstanceParameter = instanceParameter;
if (property.DeclaringType != instanceType)
readInstanceParameter = Expression.Convert(instanceParameter, property.DeclaringType);
setExpression = Expression.Call(readInstanceParameter, setMethod, readValueParameter);
}
var lambda = Expression.Lambda(actionType, setExpression, instanceParameter, valueParameter);
var result = lambda.Compile();
return result;
}
#endregion
#region GetEventAdder
private static YieldReaderWriterLockSlim _addEventLock;
private static readonly Dictionary<EventInfo, Action<object, Delegate>> _addEventDictionary = new Dictionary<EventInfo, Action<object, Delegate>>();
private static readonly Func<EventInfo, Action<object, Delegate>> _getEventAdderDelegate = GetEventAdderDelegate<object, Delegate>;
/// <summary>
/// Gets a delegate to do fast "event add"
/// </summary>
public static Action<object, Delegate> GetEventAdderDelegate(EventInfo eventInfo)
{
var result = _addEventDictionary.GetOrCreateValue(ref _addEventLock, eventInfo, _getEventAdderDelegate);
return result;
}
/// <summary>
/// Gets a delegate to do fast "event add".
/// Can avoid casts if the right generic types are given.
/// </summary>
public static Action<TInstance, TDelegate> GetEventAdderDelegate<TInstance, TDelegate>(EventInfo eventInfo)
{
return _GetEventDelegate<TInstance, TDelegate>(eventInfo.GetAddMethod(), eventInfo.EventHandlerType);
}
#endregion
#region GetEventRemoverDelegate
private static YieldReaderWriterLockSlim _removeEventLock;
private static readonly Dictionary<EventInfo, Action<object, Delegate>> _removeEventDictionary = new Dictionary<EventInfo, Action<object, Delegate>>();
private static readonly Func<EventInfo, Action<object, Delegate>> _getEventRemoverDelegate = GetEventRemoverDelegate<object, Delegate>;
/// <summary>
/// Gets a delegate to do fast "event remove" calls.
/// </summary>
public static Action<object, Delegate> GetEventRemoverDelegate(EventInfo eventInfo)
{
var result = _removeEventDictionary.GetOrCreateValue(ref _removeEventLock, eventInfo, _getEventRemoverDelegate);
return result;
}
/// <summary>
/// Gets a delegate to do fast "event remove" calls.
/// Can avoid casts if the right generic types are given.
/// </summary>
public static Action<TInstance, TDelegate> GetEventRemoverDelegate<TInstance, TDelegate>(EventInfo eventInfo)
{
return _GetEventDelegate<TInstance, TDelegate>(eventInfo.GetRemoveMethod(), eventInfo.EventHandlerType);
}
#endregion
#region _GetEventDelegate
private static Action<TInstance, TDelegate> _GetEventDelegate<TInstance, TDelegate>(MethodInfo method, Type handlerType)
{
var instanceParameter = Expression.Parameter(typeof(TInstance), "instance");
var handlerParameter = Expression.Parameter(typeof(TDelegate), "handler");
Expression readHandlerParameter = handlerParameter;
if (handlerType != typeof(TDelegate))
readHandlerParameter = Expression.Convert(handlerParameter, handlerType);
Expression callExpression;
if (method.IsStatic)
callExpression = Expression.Call(method, readHandlerParameter);
else
{
Expression readInstanceParameter = instanceParameter;
if (method.DeclaringType != typeof(TInstance))
readInstanceParameter = Expression.Convert(instanceParameter, method.DeclaringType);
callExpression = Expression.Call(readInstanceParameter, method, readHandlerParameter);
}
var lambda = Expression.Lambda<Action<TInstance, TDelegate>>(callExpression, instanceParameter, handlerParameter);
var result = lambda.Compile();
return result;
}
#endregion
#region GetFieldGetterDelegate
private static YieldReaderWriterLockSlim _getFieldLock;
private static readonly Dictionary<FieldInfo, Func<object, object>> _getFieldsDictionary = new Dictionary<FieldInfo,Func<object, object>>();
private static readonly Func<FieldInfo, Func<object, object>> _getFieldGetterDelegate = GetFieldGetterDelegate<object, object>;
/// <summary>
/// Gets a delegate to read values from the given field in a very fast manner.
/// </summary>
public static Func<object, object> GetFieldGetterDelegate(FieldInfo field)
{
var result = _getFieldsDictionary.GetOrCreateValue(ref _getFieldLock, field, _getFieldGetterDelegate);
return result;
}
private static YieldReaderWriterLockSlim _getTypedFieldLock;
private static readonly Dictionary<KeyValuePair<Type, FieldInfo>, Delegate> _getTypedFieldsDictionary = new Dictionary<KeyValuePair<Type, FieldInfo>, Delegate>();
private static readonly Func<KeyValuePair<Type, FieldInfo>, Delegate> _getTypedFieldGetterDelegate = _GetFieldGetterDelegate;
/// <summary>
/// Gets a delegate to read values from the given field in a very fast manner.
/// The result will be already cast or will even avoid casts if the
/// generic types are correct.
/// </summary>
public static Func<TInstance, TOutput> GetFieldGetterDelegate<TInstance, TOutput>(FieldInfo field)
{
if (field == null)
throw new ArgumentNullException("field");
var pair = Pair.Create(typeof(Func<TInstance, TOutput>), field);
var result = _getTypedFieldsDictionary.GetOrCreateValue(ref _getTypedFieldLock, pair, _getTypedFieldGetterDelegate);
return (Func<TInstance, TOutput>)result;
}
private static Delegate _GetFieldGetterDelegate(KeyValuePair<Type, FieldInfo> pair)
{
var funcType = pair.Key;
var field = pair.Value;
var funcArguments = funcType.GetGenericArguments();
var instanceType = funcArguments[0];
var resultType = funcArguments[1];
var parameter = Expression.Parameter(instanceType, "instance");
Expression resultExpression;
if (field.IsStatic)
resultExpression = Expression.MakeMemberAccess(null, field);
else
{
Expression readParameter = parameter;
if (field.DeclaringType != instanceType)
readParameter = Expression.Convert(parameter, field.DeclaringType);
resultExpression = Expression.MakeMemberAccess(readParameter, field);
}
if (field.FieldType != resultType)
resultExpression = Expression.Convert(resultExpression, resultType);
var lambda = Expression.Lambda(funcType, resultExpression, parameter);
var result = lambda.Compile();
return result;
}
#endregion
#if !WINDOWS_PHONE
#region GetFastDynamicDelegate
/// <summary>
/// You have an untyped delegate? Then get another delegate to invoke it faster.
/// </summary>
public static FastDynamicDelegate GetFastDynamicDelegate(Delegate realDelegate)
{
var result = ReflectionHelper.GetMethodCallDelegate(realDelegate.Method);
return (parameters) => result(realDelegate.Target, parameters);
}
#endregion
#endif
}
/// <summary>
/// This is a typed version of reflection helper, so your expression already starts with a know
/// object type (used when you don't have an already instantiated object).
/// </summary>
public static class ReflectionHelper<ForType>
{
#region GetMember
/// <summary>
/// Gets a member by it's expression usage.
/// For example, GetMember((obj) => obj.GetType()) will return the
/// GetType method.
/// </summary>
public static MemberInfo GetMember<T>(Expression<Func<ForType, T>> expression)
{
if (expression == null)
throw new ArgumentNullException("expression");
var body = expression.Body;
switch(body.NodeType)
{
case ExpressionType.MemberAccess:
MemberExpression memberExpression = (MemberExpression)body;
return memberExpression.Member;
case ExpressionType.Call:
MethodCallExpression callExpression = (MethodCallExpression)body;
return callExpression.Method;
case ExpressionType.New:
NewExpression newExpression = (NewExpression)body;
return newExpression.Constructor;
}
throw new ArgumentException("expression.Body must be a member or call expression.", "expression");
}
#endregion
#region GetField
/// <summary>
/// Gets a field from a sample usage.
/// Example: GetField((obj) => obj.SomeField) will return the FieldInfo of
/// EmptyTypes.
/// </summary>
public static FieldInfo GetField<T>(Expression<Func<ForType, T>> expression)
{
return (FieldInfo)GetMember(expression);
}
#endregion
#region GetProperty
/// <summary>
/// Gets a property from a sample usage.
/// Example: GetProperty((str) => str.Length) will return the property info
/// of Length.
/// </summary>
public static PropertyInfo GetProperty<T>(Expression<Func<ForType, T>> expression)
{
return (PropertyInfo)GetMember(expression);
}
#endregion
#region GetMethod
/// <summary>
/// Gets a method info of a void method.
/// Example: GetMethod((obj) => obj.SomeCall("")); will return the
/// MethodInfo of SomeCall that receives a single argument.
/// </summary>
public static MethodInfo GetMethod(Expression<Action<ForType>> expression)
{
if (expression == null)
throw new ArgumentNullException("expression");
var body = expression.Body;
if (body.NodeType != ExpressionType.Call)
throw new ArgumentException("expression.Body must be a Call expression.", "expression");
MethodCallExpression callExpression = (MethodCallExpression)body;
return callExpression.Method;
}
/// <summary>
/// Gets the MethodInfo of a method that returns a value.
/// Example: GetMethod((obj) => obj.SomeCall()); will return the method info
/// of SomeCall.
/// </summary>
public static MethodInfo GetMethod<T>(Expression<Func<ForType, T>> expression)
{
return (MethodInfo)GetMember(expression);
}
#endregion
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C#
1
https://gitee.com/deu2019/pzf.git
[email protected]:deu2019/pzf.git
deu2019
pzf
pzf
master

搜索帮助