mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
5.7 KiB
174 lines
5.7 KiB
// ==========================================================================
|
|
// SimpleMapper.cs
|
|
// PinkParrot Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) PinkParrot Group
|
|
// All rights reserved.
|
|
// ==========================================================================
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
|
|
// ReSharper disable StaticMemberInGenericType
|
|
|
|
namespace PinkParrot.Infrastructure.Reflection
|
|
{
|
|
public static class SimpleMapper
|
|
{
|
|
private sealed class ConversionPropertyMapper : PropertyMapper
|
|
{
|
|
private readonly Type targetType;
|
|
|
|
public ConversionPropertyMapper(IPropertyAccessor srcAccessor, IPropertyAccessor dstAccessor, Type targetType)
|
|
: base(srcAccessor, dstAccessor)
|
|
{
|
|
this.targetType = targetType;
|
|
}
|
|
|
|
public override void Map(object source, object destination, CultureInfo culture)
|
|
{
|
|
var value = GetValue(source);
|
|
|
|
if (value == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
object converted;
|
|
try
|
|
{
|
|
converted = Convert.ChangeType(value, targetType, culture);
|
|
|
|
SetValue(destination, converted);
|
|
}
|
|
catch (InvalidCastException)
|
|
{
|
|
if (targetType == typeof(string))
|
|
{
|
|
converted = value.ToString();
|
|
|
|
SetValue(destination, converted);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private class PropertyMapper
|
|
{
|
|
private readonly IPropertyAccessor srcAccessor;
|
|
private readonly IPropertyAccessor dstAccessor;
|
|
|
|
public PropertyMapper(IPropertyAccessor srcAccessor, IPropertyAccessor dstAccessor)
|
|
{
|
|
this.srcAccessor = srcAccessor;
|
|
this.dstAccessor = dstAccessor;
|
|
}
|
|
|
|
public virtual void Map(object source, object destination, CultureInfo culture)
|
|
{
|
|
var value = GetValue(source);
|
|
|
|
SetValue(destination, value);
|
|
}
|
|
|
|
protected void SetValue(object destination, object value)
|
|
{
|
|
dstAccessor.Set(destination, value);
|
|
}
|
|
|
|
protected object GetValue(object source)
|
|
{
|
|
return srcAccessor.Get(source);
|
|
}
|
|
}
|
|
|
|
private static class ClassMapper<TSource, TDestination>
|
|
where TSource : class
|
|
where TDestination : class
|
|
{
|
|
private static readonly PropertyMapper[] Mappers;
|
|
|
|
private static readonly Type[] Convertibles =
|
|
{
|
|
typeof(bool),
|
|
typeof(byte),
|
|
typeof(char),
|
|
typeof(decimal),
|
|
typeof(float),
|
|
typeof(double),
|
|
typeof(short),
|
|
typeof(int),
|
|
typeof(long),
|
|
typeof(string),
|
|
typeof(DateTime)
|
|
};
|
|
|
|
static ClassMapper()
|
|
{
|
|
var dstType = typeof(TDestination);
|
|
var srcType = typeof(TSource);
|
|
|
|
var destinationProperties = dstType.GetPublicProperties();
|
|
|
|
var newMappers = new List<PropertyMapper>();
|
|
|
|
foreach (var srcProperty in srcType.GetPublicProperties().Where(x => x.CanRead))
|
|
{
|
|
var dstProperty = destinationProperties.FirstOrDefault(x => x.Name == srcProperty.Name);
|
|
|
|
if (dstProperty == null || !dstProperty.CanWrite)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var srcPropertyType = srcProperty.PropertyType;
|
|
var dstPropertyType = dstProperty.PropertyType;
|
|
|
|
if (srcPropertyType == dstPropertyType)
|
|
{
|
|
newMappers.Add(new PropertyMapper(new PropertyAccessor(srcType, srcProperty), new PropertyAccessor(dstType, dstProperty)));
|
|
}
|
|
else
|
|
{
|
|
if (Convertibles.Contains(dstPropertyType))
|
|
{
|
|
newMappers.Add(new ConversionPropertyMapper(new PropertyAccessor(srcType, srcProperty), new PropertyAccessor(dstType, dstProperty), dstPropertyType));
|
|
}
|
|
}
|
|
}
|
|
|
|
Mappers = newMappers.ToArray();
|
|
}
|
|
|
|
public static TDestination Map(TSource source, TDestination destination, CultureInfo culture)
|
|
{
|
|
foreach (var mapper in Mappers)
|
|
{
|
|
mapper.Map(source, destination, culture);
|
|
}
|
|
|
|
return destination;
|
|
}
|
|
}
|
|
|
|
public static TDestination Map<TSource, TDestination>(TSource source, TDestination destination)
|
|
where TSource : class
|
|
where TDestination : class
|
|
{
|
|
return Map(source, destination, CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
public static TDestination Map<TSource, TDestination>(TSource source, TDestination destination, CultureInfo culture)
|
|
where TSource : class
|
|
where TDestination : class
|
|
{
|
|
Guard.NotNull(source, nameof(source));
|
|
Guard.NotNull(culture, nameof(culture));
|
|
Guard.NotNull(destination, nameof(destination));
|
|
|
|
return ClassMapper<TSource, TDestination>.Map(source, destination, culture);
|
|
}
|
|
}
|
|
}
|
|
|