Refactor model type mapping in IPublishedModelFactory

This commit is contained in:
Stephan
2017-10-17 09:07:01 +02:00
parent c62513bd04
commit cfe5350269
6 changed files with 58 additions and 40 deletions

View File

@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections;
namespace Umbraco.Core.Models.PublishedContent
{
@@ -17,9 +17,18 @@ namespace Umbraco.Core.Models.PublishedContent
IPublishedElement CreateModel(IPublishedElement element);
/// <summary>
/// Gets the model type map.
/// Creates a List{T} of a strongly-typed model for a model type alias.
/// </summary>
/// <remarks>The model type map maps element type aliases to actual Clr types.</remarks>
Dictionary<string, Type> ModelTypeMap { get; }
/// <param name="alias">The model type alias.</param>
/// <returns>A List{T} of the strongly-typed model, exposed as an IList.</returns>
IList CreateModelList(string alias);
/// <summary>
/// Maps a Clr type that may contain model types, to an actual Clr type.
/// </summary>
/// <param name="type">The Clr type.</param>
/// <returns>The actual Clr type.</returns>
/// <remarks>See <seealso cref="ModelType"/> for more details.</remarks>
Type MapModelType(Type type);
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Umbraco.Core.Models.PublishedContent
@@ -11,6 +12,9 @@ namespace Umbraco.Core.Models.PublishedContent
public IPublishedElement CreateModel(IPublishedElement element) => element;
/// <inheritdoc />
public Dictionary<string, Type> ModelTypeMap { get; } = new Dictionary<string, Type>();
public IList CreateModelList(string alias) => new List<IPublishedElement>();
/// <inheritdoc />
public Type MapModelType(Type type) => typeof(IPublishedElement);
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
@@ -10,16 +11,16 @@ namespace Umbraco.Core.Models.PublishedContent
public class PublishedModelFactory : IPublishedModelFactory
{
private readonly Dictionary<string, ModelInfo> _modelInfos;
private readonly Dictionary<string, Type> _modelTypeMap;
private class ModelInfo
{
public Type ParameterType { get; set; }
public Func<object, object> Ctor { get; set; }
public Type ModelType { get; set; }
public Func<IList> ListCtor { get; set; }
}
public Dictionary<string, Type> ModelTypeMap { get; }
/// <summary>
/// Initializes a new instance of the <see cref="PublishedModelFactory"/> class with types.
/// </summary>
@@ -37,7 +38,7 @@ namespace Umbraco.Core.Models.PublishedContent
public PublishedModelFactory(IEnumerable<Type> types)
{
var modelInfos = new Dictionary<string, ModelInfo>(StringComparer.InvariantCultureIgnoreCase);
ModelTypeMap = new Dictionary<string, Type>(StringComparer.InvariantCultureIgnoreCase);
var modelTypeMap = new Dictionary<string, Type>(StringComparer.InvariantCultureIgnoreCase);
foreach (var type in types)
{
@@ -72,19 +73,21 @@ namespace Umbraco.Core.Models.PublishedContent
// have to use an unsafe ctor because we don't know the types, really
var modelCtor = ReflectionUtilities.EmitCtorUnsafe<Func<object, object>>(constructor);
modelInfos[typeName] = new ModelInfo { ParameterType = parameterType, ModelType = type, Ctor = modelCtor };
ModelTypeMap[typeName] = type;
modelTypeMap[typeName] = type;
}
_modelInfos = modelInfos.Count > 0 ? modelInfos : null;
_modelTypeMap = modelTypeMap;
}
/// <inheritdoc />
public IPublishedElement CreateModel(IPublishedElement element)
{
// fail fast
if (_modelInfos == null)
return element;
if (_modelInfos.TryGetValue(element.ContentType.Alias, out var modelInfo) == false)
if (!_modelInfos.TryGetValue(element.ContentType.Alias, out var modelInfo))
return element;
// ReSharper disable once UseMethodIsInstanceOfType
@@ -94,5 +97,27 @@ namespace Umbraco.Core.Models.PublishedContent
// can cast, because we checked when creating the ctor
return (IPublishedElement) modelInfo.Ctor(element);
}
/// <inheritdoc />
public IList CreateModelList(string alias)
{
// fail fast
if (_modelInfos == null)
return new List<IPublishedElement>();
if (!_modelInfos.TryGetValue(alias, out var modelInfo))
return new List<IPublishedElement>();
var ctor = modelInfo.ListCtor;
if (ctor != null) return ctor();
var listType = typeof(List<>).MakeGenericType(modelInfo.ModelType);
ctor = modelInfo.ListCtor = ReflectionUtilities.EmitCtor<Func<IList>>(declaring: listType);
return ctor();
}
/// <inheritdoc />
public Type MapModelType(Type type)
=> ModelType.Map(type, _modelTypeMap);
}
}

View File

@@ -280,7 +280,7 @@ namespace Umbraco.Core.Models.PublishedContent
get
{
if (!_initialized) Initialize();
return _clrType ?? (_clrType = ModelType.Map(_modelClrType, Current.PublishedModelFactory.ModelTypeMap));
return _clrType ?? (_clrType = Current.PublishedModelFactory.MapModelType(_modelClrType));
}
}