//--------------------------------------------------------------------- // This file is part of the Background Motion solution. // // Copyright (C) Mindscape (TM). All rights reserved. // http://www.mindscape.co.nz // // THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. //--------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Reflection; namespace Mindscape.BackgroundMotion.Core.Utilities { /// <summary> /// Provides a simple reflection based mapper to perform a Data Mapping between two types of objects /// </summary> /// <remarks> /// We are working on the convention that the source object will be property based and the target will be field based /// This is used between our domain entities and DTO's /// </remarks> /// <typeparam name="T"></typeparam> public class DataMapper<T> where T : new() { // TODO: Not thread-safe - using ThreadStatic should be ok here private static Dictionary<Type, Dictionary<string, PropertyInfo>> _propertyReflectionCache = new Dictionary<Type, Dictionary<string, PropertyInfo>>(); private static Dictionary<Type, FieldInfo[]> _fieldReflectionCache = new Dictionary<Type, FieldInfo[]>(); /// <summary> /// Use a reflection based mapping to map between properties and fields /// </summary> public static T Map(object source) { T target = new T(); FieldInfo[] fields = GetFieldSetInfo(typeof(T)); if (source == null) { return target; } foreach (FieldInfo field in fields) { try { PropertyInfo sourceProperty = GetPropertyInfo(source.GetType(), field.Name); if (sourceProperty == null) { continue; } field.SetValue(target, sourceProperty.GetValue(source, null)); } catch (InvalidCastException) { } } return target; } /// <summary> /// Finds a property in the reflection cache /// </summary> private static PropertyInfo GetPropertyInfo(Type t, string name) { if (_propertyReflectionCache.ContainsKey(t)) { if (_propertyReflectionCache[t].ContainsKey(name)) { return _propertyReflectionCache[t][name]; } _propertyReflectionCache[t].Add(name, t.GetProperty(name, BindingFlags.Public | BindingFlags.Instance)); return _propertyReflectionCache[t][name]; } Dictionary<string, PropertyInfo> dictionary = new Dictionary<string, PropertyInfo>(); _propertyReflectionCache.Add(t, dictionary); dictionary.Add(name, t.GetProperty(name, BindingFlags.Public | BindingFlags.Instance)); return _propertyReflectionCache[t][name]; } /// <summary> /// Finds a collection of field information from the reflection cache /// </summary> private static FieldInfo[] GetFieldSetInfo(Type t) { if (_fieldReflectionCache.ContainsKey(t)) { return _fieldReflectionCache[t]; } _fieldReflectionCache.Add(t, t.GetFields(BindingFlags.Public | BindingFlags.Instance)); return _fieldReflectionCache[t]; } } }