Psst.. new poll here.
[email protected] web/email now available. Want one? Go here.
Cannot use outlook/hotmail/live here to register as they blocking our mail servers. #microsoftdeez
Obey the Epel!
Paste
Pasted as C# by atakan ( 2 years ago )
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
namespace Peak.Common.ObjectMapper
{
/// <summary>
/// ObjectMapper.ILMapper
/// </summary>
public static class ILMapper
{
private static readonly ConcurrentDictionary<(Type Source, Type Destination), Func<object, object>> _delegateCache = new ConcurrentDictionary<(Type Source, Type Destination), Func<object, object>>();
private static readonly Type _tObject = typeof(object);
/// <summary>
/// Maps two identical objects via IL Generator with respect to performance. (target is not reference type)
/// </summary>
/// <typeparam name="TTgt"></typeparam>
/// <param name="source"></param>
/// <param name="stringPropNullSafe">map null source properties as string.Empty to target</param>
/// <param name="target"></param>
/// <returns></returns>
public static TTgt Convert<TTgt>(object source, TTgt target, bool stringPropNullSafe = false) where TTgt : new()
{
var del = _delegateCache.GetOrAdd((source.GetType(), typeof(TTgt)), t =>
{
var dm = new DynamicMethod(
GenerateMethodName(t.Source, t.Destination),
_tObject,
new[] { _tObject },
t.Source.Module);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Newobj, t.Destination.GetConstructor(new Type[] { }));
foreach (var map in GetMatchingProperties(t.Source, t.Destination))
{
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Callvirt, map.SourceProperty.GetGetMethod(), null);
if (stringPropNullSafe)
{
var isString = map.SourceProperty.PropertyType == typeof(string);
if (isString)
{
var notNull = il.DefineLabel();
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Brtrue_S, notNull);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldstr, string.Empty);
il.MarkLabel(notNull);
}
}
il.EmitCall(OpCodes.Callvirt, map.TargetProperty.GetSetMethod(), null);
}
il.Emit(OpCodes.Ret);
return (Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>));
});
return (TTgt)del(source);
}
/// <summary>
/// Maps two identical objects via IL Generator with respect to performance. (target is reference type)
/// </summary>
/// <typeparam name="TTgt"></typeparam>
/// <param name="source"></param>
/// <param name="target"></param>
/// <param name="stringPropNullSafe">map null source properties as string.Empty to target</param>
/// <returns></returns>
public static TTgt Convert<TTgt>(object source, ref TTgt target, bool stringPropNullSafe = false) where TTgt : new()
{
target = Convert(source,target,stringPropNullSafe);
return target;
}
#region Private Methods
private static IEnumerable<PropertyMap> GetMatchingProperties(Type sourceType, Type targetType)
{
var sourceProperties = sourceType.GetProperties();
var targetProperties = targetType.GetProperties();
return (sourceProperties
.SelectMany(s => targetProperties, (s, t) => new { s, t })
.Where(p =>
p.s.Name == p.t.Name
&& p.s.CanRead
&& p.t.CanWrite)
.Select(p => new PropertyMap { SourceProperty = p.s, TargetProperty = p.t }))
.ToList();
}
private static string GenerateMethodName(Type sourceType, Type targetType) =>
$"Copy_{sourceType.FullName.Replace(".", "_").Replace("+", "_")}_{targetType.FullName.Replace(".", "_").Replace("+", "_")}";
#endregion
}
}
Revise this Paste
Parent: 124477