Eliminate use of method groups in PropertyHelper (dotnet/extensions#465)

* Eliminate use of method groups, and use for loop to enumerate elements of array.

Improves performance and reduces allocations.

* PR feedback:
Remove extra parentheses, and undo change from foreach to for loop.

* PR feedback
Revert change from for to foreach.

* var-ify TryGetValue out parameter.
\n\nCommit migrated from 08adb5c2ca
This commit is contained in:
Gert Driesen 2018-11-13 19:03:55 +01:00 committed by Ryan Nowak
parent 755b35295f
commit 83c88bd6bd
1 changed files with 9 additions and 13 deletions

View File

@ -7,7 +7,6 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
namespace Microsoft.Extensions.Internal namespace Microsoft.Extensions.Internal
{ {
@ -145,7 +144,7 @@ namespace Microsoft.Extensions.Internal
/// </returns> /// </returns>
public static PropertyHelper[] GetProperties(Type type) public static PropertyHelper[] GetProperties(Type type)
{ {
return GetProperties(type, CreateInstance, PropertiesCache); return GetProperties(type, p => CreateInstance(p), PropertiesCache);
} }
/// <summary> /// <summary>
@ -164,7 +163,7 @@ namespace Microsoft.Extensions.Internal
/// </returns> /// </returns>
public static PropertyHelper[] GetVisibleProperties(TypeInfo typeInfo) public static PropertyHelper[] GetVisibleProperties(TypeInfo typeInfo)
{ {
return GetVisibleProperties(typeInfo.AsType(), CreateInstance, PropertiesCache, VisiblePropertiesCache); return GetVisibleProperties(typeInfo.AsType(), p => CreateInstance(p), PropertiesCache, VisiblePropertiesCache);
} }
/// <summary> /// <summary>
@ -183,7 +182,7 @@ namespace Microsoft.Extensions.Internal
/// </returns> /// </returns>
public static PropertyHelper[] GetVisibleProperties(Type type) public static PropertyHelper[] GetVisibleProperties(Type type)
{ {
return GetVisibleProperties(type, CreateInstance, PropertiesCache, VisiblePropertiesCache); return GetVisibleProperties(type, p => CreateInstance(p), PropertiesCache, VisiblePropertiesCache);
} }
/// <summary> /// <summary>
@ -420,8 +419,7 @@ namespace Microsoft.Extensions.Internal
ConcurrentDictionary<Type, PropertyHelper[]> allPropertiesCache, ConcurrentDictionary<Type, PropertyHelper[]> allPropertiesCache,
ConcurrentDictionary<Type, PropertyHelper[]> visiblePropertiesCache) ConcurrentDictionary<Type, PropertyHelper[]> visiblePropertiesCache)
{ {
PropertyHelper[] result; if (visiblePropertiesCache.TryGetValue(type, out var result))
if (visiblePropertiesCache.TryGetValue(type, out result))
{ {
return result; return result;
} }
@ -497,18 +495,17 @@ namespace Microsoft.Extensions.Internal
// part of the sequence of properties returned by this method. // part of the sequence of properties returned by this method.
type = Nullable.GetUnderlyingType(type) ?? type; type = Nullable.GetUnderlyingType(type) ?? type;
PropertyHelper[] helpers; if (!cache.TryGetValue(type, out var helpers))
if (!cache.TryGetValue(type, out helpers))
{ {
// We avoid loading indexed properties using the Where statement. // We avoid loading indexed properties using the Where statement.
var properties = type.GetRuntimeProperties().Where(IsInterestingProperty); var properties = type.GetRuntimeProperties().Where(p => IsInterestingProperty(p));
var typeInfo = type.GetTypeInfo(); var typeInfo = type.GetTypeInfo();
if (typeInfo.IsInterface) if (typeInfo.IsInterface)
{ {
// Reflection does not return information about inherited properties on the interface itself. // Reflection does not return information about inherited properties on the interface itself.
properties = properties.Concat(typeInfo.ImplementedInterfaces.SelectMany( properties = properties.Concat(typeInfo.ImplementedInterfaces.SelectMany(
interfaceType => interfaceType.GetRuntimeProperties().Where(IsInterestingProperty))); interfaceType => interfaceType.GetRuntimeProperties().Where(p => IsInterestingProperty(p))));
} }
helpers = properties.Select(p => createPropertyHelper(p)).ToArray(); helpers = properties.Select(p => createPropertyHelper(p)).ToArray();
@ -518,17 +515,16 @@ namespace Microsoft.Extensions.Internal
return helpers; return helpers;
} }
private static bool IsInterestingProperty(PropertyInfo property) private static bool IsInterestingProperty(PropertyInfo property)
{ {
// For improving application startup time, do not use GetIndexParameters() api early in this check as it // For improving application startup time, do not use GetIndexParameters() api early in this check as it
// creates a copy of parameter array and also we would like to check for the presence of a get method // creates a copy of parameter array and also we would like to check for the presence of a get method
// and short circuit asap. // and short circuit asap.
return return
property.GetMethod != null && property.GetMethod != null &&
property.GetMethod.IsPublic && property.GetMethod.IsPublic &&
!property.GetMethod.IsStatic && !property.GetMethod.IsStatic &&
// PropertyHelper can't work with ref structs. // PropertyHelper can't work with ref structs.
!IsRefStructProperty(property) && !IsRefStructProperty(property) &&