--
看一下方法:MakeFastPropertyGetter
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
namespace Microsoft.AspNet.Mvc
{
internal class PropertyHelper
{
// Delegate type for a by-ref property getter
private delegate TValue ByRefFunc<TDeclaringType, TValue>(ref TDeclaringType arg);
private static readonly MethodInfo CallPropertyGetterOpenGenericMethod =
typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod("CallPropertyGetter");
private static readonly MethodInfo CallPropertyGetterByReferenceOpenGenericMethod =
typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod("CallPropertyGetterByReference");
private static readonly MethodInfo CallPropertySetterOpenGenericMethod =
typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod("CallPropertySetter");
private static readonly ConcurrentDictionary<Type, PropertyHelper[]> ReflectionCache =
new ConcurrentDictionary<Type, PropertyHelper[]>();
private readonly Func<object, object> _valueGetter;
/// <summary>
/// Initializes a fast property helper.
///
/// This constructor does not cache the helper. For caching, use GetProperties.
/// </summary>
public PropertyHelper([NotNull] PropertyInfo property)
{
Property = property;
Name = property.Name;
_valueGetter = MakeFastPropertyGetter(property);
}
public PropertyInfo Property { get; private set; }
public virtual string Name { get; protected set; }
public object GetValue(object instance)
{
return _valueGetter(instance);
}
/// <summary>
/// Creates and caches fast property helpers that expose getters for every public get property on the
/// underlying type.
/// </summary>
/// <param name="instance">the instance to extract property accessors for.</param>
/// <returns>a cached array of all public property getters from the underlying type of target instance.
/// </returns>
public static PropertyHelper[] GetProperties(object instance)
{
return GetProperties(instance.GetType());
}
/// <summary>
/// Creates and caches fast property helpers that expose getters for every public get property on the
/// specified type.
/// </summary>
/// <param name="type">the type to extract property accessors for.</param>
/// <returns>a cached array of all public property getters from the type of target instance.
/// </returns>
public static PropertyHelper[] GetProperties(Type type)
{
return GetProperties(type, CreateInstance, ReflectionCache);
}
/// <summary>
/// Creates a single fast property getter. The result is not cached.
/// </summary>
/// <param name="propertyInfo">propertyInfo to extract the getter for.</param>
/// <returns>a fast getter.</returns>
/// <remarks>
/// This method is more memory efficient than a dynamically compiled lambda, and about the
/// same speed.
/// </remarks>
public static Func<object, object> MakeFastPropertyGetter(PropertyInfo propertyInfo)
{
Debug.Assert(propertyInfo != null);
var getMethod = propertyInfo.GetMethod;
Debug.Assert(getMethod != null);
Debug.Assert(!getMethod.IsStatic);
Debug.Assert(getMethod.GetParameters().Length == 0);
// Instance methods in the CLR can be turned into static methods where the first parameter
// is open over "target". This parameter is always passed by reference, so we have a code
// path for value types and a code path for reference types.
// 要分成两类 值类型struct中的方法 引用类型Class中的方法
/*
public class MyStruct()
{
public string Name {get;set;}
}
typeInput=typeof(MyStruct);
typeOutput=typeof(string);
public class MyClass()
{
public string Name {get;set;}
}
typeInput=typeof(MyClass);
typeOutput=typeof(string);
*/
var typeInput = getMethod.DeclaringType;
var typeOutput = getMethod.ReturnType;
Delegate callPropertyGetterDelegate;
if (typeInput.IsValueType()) // 是 struct 不是 class
{
// Create a delegate (ref TDeclaringType) -> TValue
var delegateType = typeof(ByRefFunc<,>).MakeGenericType(typeInput, typeOutput);
// delegateType=typeof(ByRefFunc<MyStruct,string>);
var propertyGetterAsFunc = getMethod.CreateDelegate(delegateType);
// delegate string propertyGetterAsFunc(ref MyStruct a)
var callPropertyGetterClosedGenericMethod =
CallPropertyGetterByReferenceOpenGenericMethod.MakeGenericMethod(typeInput, typeOutput);
/*
---------open
private static object CallPropertyGetterByReference<TDeclaringType, TValue>(
ByRefFunc<TDeclaringType, TValue> getter, object target)
{
var unboxed = (TDeclaringType)target;
return getter(ref unboxed);
}
callPropertyGetterClosedGenericMethod 下方
private satic object CallPropertyGetterByReference(ByRefFunc<MyStruct,string> getter,object target)
{
var unboxed = (MyStruct)target;
return getter(ref unboxed);
}
public class C
{
private int id;
public C(int id) { this.id = id; }
public void M1(string s)
{
Console.WriteLine("Instance method M1 on C: id = {0}, s = {1}",
this.id, s);
}
public static void M2(string s)
{
Console.WriteLine("Static method M2 on C: s = {0}", s);
}
}
public delegate void D1(C c, string s);
public delegate void D2(string s);
public delegate void D3();
MethodInfo mi1 = typeof(C).GetMethod("M1", BindingFlags.Public | BindingFlags.Instance);
MethodInfo mi2 = typeof(C).GetMethod("M2", BindingFlags.Public | BindingFlags.Static);
public static Delegate CreateDelegate (Type type,Object firstArgument,MethodInfo method,bool throwOnBindFailure)
Delegate test = Delegate.CreateDelegate(typeof(D2), c1, mi1, false);
d1 = (D1) Delegate.CreateDelegate(typeof(D1), null, mi1);
// An instance of C must be passed in each time the
// delegate is invoked.
//
d1(c1, "Hello, World!");
d1(new C(5280), "Hi, Mom!");
*/
callPropertyGetterDelegate =
callPropertyGetterClosedGenericMethod.CreateDelegate(
typeof(Func<object, object>), propertyGetterAsFunc);
/*
private satic object CallPropertyGetterByReference(ByRefFunc<MyStruct,string> getter,object target)
要变成 string function (object)
参数是 delegate string propertyGetterAsFunc(ref MyStruct a)
ByRefFunc<MyStruct,string> getter
var unboxed = (ByRefFunc<MyStruct,string>) delegate string propertyGetterAsFunc(ref MyStruct a);
return getter(ref unboxed);
执行 delegate string propertyGetterAsFunc(ref MyStruct a);
*/
}
else // 是class
{
// Create a delegate TDeclaringType -> TValue
var propertyGetterAsFunc =
getMethod.CreateDelegate(typeof(Func<,>).MakeGenericType(typeInput, typeOutput));
var callPropertyGetterClosedGenericMethod =
CallPropertyGetterOpenGenericMethod.MakeGenericMethod(typeInput, typeOutput);
callPropertyGetterDelegate =
callPropertyGetterClosedGenericMethod.CreateDelegate(
typeof(Func<object, object>), propertyGetterAsFunc);
}
return (Func<object, object>)callPropertyGetterDelegate;
}
/// <summary>
/// Creates a single fast property setter for reference types. The result is not cached.
/// </summary>
/// <param name="propertyInfo">propertyInfo to extract the setter for.</param>
/// <returns>a fast getter.</returns>
/// <remarks>
/// This method is more memory efficient than a dynamically compiled lambda, and about the
/// same speed. This only works for reference types.
/// </remarks>
public static Action<object, object> MakeFastPropertySetter(PropertyInfo propertyInfo)
{
Debug.Assert(propertyInfo != null);
Debug.Assert(!propertyInfo.DeclaringType.GetTypeInfo().IsValueType);
var setMethod = propertyInfo.SetMethod;
Debug.Assert(setMethod != null);
Debug.Assert(!setMethod.IsStatic);
Debug.Assert(setMethod.ReturnType == typeof(void));
var parameters = setMethod.GetParameters();
Debug.Assert(parameters.Length == 1);
// Instance methods in the CLR can be turned into static methods where the first parameter
// is open over "target". This parameter is always passed by reference, so we have a code
// path for value types and a code path for reference types.
var typeInput = setMethod.DeclaringType;
var parameterType = parameters[0].ParameterType;
// Create a delegate TDeclaringType -> { TDeclaringType.Property = TValue; }
var propertySetterAsAction =
setMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(typeInput, parameterType));
var callPropertySetterClosedGenericMethod =
CallPropertySetterOpenGenericMethod.MakeGenericMethod(typeInput, parameterType);
var callPropertySetterDelegate =
callPropertySetterClosedGenericMethod.CreateDelegate(
typeof(Action<object, object>), propertySetterAsAction);
return (Action<object, object>)callPropertySetterDelegate;
}
private static PropertyHelper CreateInstance(PropertyInfo property)
{
return new PropertyHelper(property);
}
// Called via reflection
private static object CallPropertyGetter<TDeclaringType, TValue>(
Func<TDeclaringType, TValue> getter,
object target)
{
return getter((TDeclaringType)target);
}
// Called via reflection
private static object CallPropertyGetterByReference<TDeclaringType, TValue>(
ByRefFunc<TDeclaringType, TValue> getter,
object target)
{
var unboxed = (TDeclaringType)target;
return getter(ref unboxed);
}
private static void CallPropertySetter<TDeclaringType, TValue>(
Action<TDeclaringType, TValue> setter,
object target,
object value)
{
setter((TDeclaringType)target, (TValue)value);
}
protected static PropertyHelper[] GetProperties(
Type type,
Func<PropertyInfo, PropertyHelper> createPropertyHelper,
ConcurrentDictionary<Type, PropertyHelper[]> cache)
{
// Unwrap nullable types. This means Nullable<T>.Value and Nullable<T>.HasValue will not be
// part of the sequence of properties returned by this method.
type = Nullable.GetUnderlyingType(type) ?? type;
// Using an array rather than IEnumerable, as target will be called on the hot path numerous times.
PropertyHelper[] helpers;
if (!cache.TryGetValue(type, out helpers))
{
// We avoid loading indexed properties using the where statement.
// Indexed properties are not useful (or valid) for grabbing properties off an object.
var properties = type.GetRuntimeProperties().Where(
prop => prop.GetIndexParameters().Length == 0 &&
prop.GetMethod != null &&
prop.GetMethod.IsPublic &&
!prop.GetMethod.IsStatic);
helpers = properties.Select(p => createPropertyHelper(p)).ToArray();
cache.TryAdd(type, helpers);
}
return helpers;
}
}
}
浙公网安备 33010602011771号