Munch on less memory when handling property metadata

- #5499
- switch `foreach` to `for` and use less Linq when accessing `modelMetadata.Properties`
- change backing field for `ModelExplorer.Properties` from a list to an array
This commit is contained in:
Doug Bunting 2016-11-24 17:11:29 -08:00
parent 48546dbb28
commit 7178464ed2
7 changed files with 50 additions and 28 deletions

View File

@ -623,7 +623,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
//
if (modelMetadata.IsEnumerableType ||
!modelMetadata.IsComplexType ||
!modelMetadata.Properties.Any())
modelMetadata.Properties.Count == 0)
{
Context.Results.Add(CreateResult(bindingContext, source ?? ambientSource, containerName));
return;
@ -656,10 +656,10 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
newContainerName = GetName(containerName, bindingContext);
}
foreach (var propertyMetadata in modelMetadata.Properties)
for (var i = 0; i < modelMetadata.Properties.Count; i++)
{
var propertyMetadata = modelMetadata.Properties[i];
var key = new PropertyKey(propertyMetadata, source);
var propertyContext = ApiParameterDescriptionContext.GetContext(
propertyMetadata,
bindingInfo: null,

View File

@ -60,8 +60,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
bindingContext.Model = CreateModel(bindingContext);
}
foreach (var property in bindingContext.ModelMetadata.Properties)
for (var i = 0; i < bindingContext.ModelMetadata.Properties.Count; i++)
{
var property = bindingContext.ModelMetadata.Properties[i];
if (!CanBindProperty(bindingContext, property))
{
continue;
@ -228,8 +229,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
//
var hasBindableProperty = false;
var isAnyPropertyEnabledForValueProviderBasedBinding = false;
foreach (var propertyMetadata in bindingContext.ModelMetadata.Properties)
for (var i = 0; i < bindingContext.ModelMetadata.Properties.Count; i++)
{
var propertyMetadata = bindingContext.ModelMetadata.Properties[i];
if (!CanBindProperty(bindingContext, propertyMetadata))
{
continue;

View File

@ -2,8 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Reflection;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -25,8 +25,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
HasDefaultConstructor(context.Metadata.ModelType.GetTypeInfo()))
{
var propertyBinders = new Dictionary<ModelMetadata, IModelBinder>();
foreach (var property in context.Metadata.Properties)
for (var i = 0; i < context.Metadata.Properties.Count; i++)
{
var property = context.Metadata.Properties[i];
propertyBinders.Add(property, context.CreateBinder(property));
}

View File

@ -463,8 +463,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Internal
}
else if (modelMetadata.IsComplexType)
{
foreach (var property in modelMetadata.Properties)
for (var i = 0; i < modelMetadata.Properties.Count; i++)
{
var property = modelMetadata.Properties[i];
modelState.ClearValidationState(property.BinderModelName ?? property.PropertyName);
}
}

View File

@ -129,9 +129,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
if (string.IsNullOrEmpty(modelKey))
{
var modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(typeof(TModel));
foreach (var property in modelMetadata.Properties)
for (var i = 0; i < modelMetadata.Properties.Count; i++)
{
var property = modelMetadata.Properties[i];
var childKey = property.BinderModelName ?? property.PropertyName;
var entries = modelState.FindKeysWithPrefix(childKey).ToArray();
foreach (var entry in entries)

View File

@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Internal;
@ -20,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
private object _model;
private Func<object, object> _modelAccessor;
private List<ModelExplorer> _properties;
private ModelExplorer[] _properties;
/// <summary>
/// Creates a new <see cref="ModelExplorer"/>.
@ -198,24 +197,38 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
/// Includes a <see cref="ModelExplorer"/> for each property of the <see cref="ModelMetadata"/>
/// for <see cref="ModelType"/>.
/// </remarks>
public IEnumerable<ModelExplorer> Properties
public IEnumerable<ModelExplorer> Properties => PropertiesInternal;
private ModelExplorer[] PropertiesInternal
{
get
{
if (_properties == null)
{
_properties = new List<ModelExplorer>();
var metadata = GetMetadataForRuntimeType();
var properties = metadata.Properties;
var propertyHelpers = PropertyHelper.GetProperties(ModelType);
var properties = Enumerable.Join(
metadata.Properties,
PropertyHelper.GetProperties(ModelType),
m => m.PropertyName,
ph => ph.Property.Name,
(m, ph) => CreateExplorerForProperty(m, ph));
_properties = new ModelExplorer[properties.Count];
for (var i = 0; i < properties.Count; i++)
{
var propertyMetadata = properties[i];
PropertyHelper propertyHelper = null;
for (var j = 0; j < propertyHelpers.Length; j++)
{
if (string.Equals(
propertyMetadata.PropertyName,
propertyHelpers[j].Property.Name,
StringComparison.Ordinal))
{
propertyHelper = propertyHelpers[j];
break;
}
}
_properties.AddRange(properties);
Debug.Assert(propertyHelper != null);
_properties[i] = CreateExplorerForProperty(propertyMetadata, propertyHelper);
}
}
return _properties;
@ -252,10 +265,16 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
throw new ArgumentNullException(nameof(name));
}
return Properties.FirstOrDefault(p => string.Equals(
p.Metadata.PropertyName,
name,
StringComparison.Ordinal));
for (var i = 0; i < PropertiesInternal.Length; i++)
{
var property = PropertiesInternal[i];
if (string.Equals(name, property.Metadata.PropertyName, StringComparison.Ordinal))
{
return property;
}
}
return null;
}
/// <summary>

View File

@ -2,9 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using System.Globalization;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Linq;
namespace Microsoft.AspNetCore.Mvc.ViewFeatures
{