/// <summary> /// Ignores a member to map by its name /// </summary> /// <typeparam name="TSource"></typeparam> /// <typeparam name="TTarget"></typeparam> /// <param name="expression"></param> /// <param name="memberName"></param> /// <returns></returns> public static IMappingExpression <TSource, TTarget> IgnoreMemberByName <TSource, TTarget>( this IMappingExpression <TSource, TTarget> expression, string memberName) { var member = TypeFinder.CachedDiscoverableProperties(typeof(TTarget)) .Where(x => x.Name == memberName) .SingleOrDefault(); if (member == null) { throw new MissingMemberException("Could not find the property " + memberName + " on type " + typeof(TTarget).FullName); } expression.MappingContext.AddMemberExpression(member.PropertyType, typeof(TTarget), memberName, opt => opt.Ignore()); return(expression); }
/// <summary> /// Copies an object graph. /// </summary> /// <param name="source">The source.</param> /// <param name="targetType">Type of the target.</param> /// <param name="factory">The factory.</param> /// <param name="recurseCount">The recurse count.</param> /// <param name="hideErrorsInPartialTrust">The hide errors in partial trust.</param> /// <returns></returns> public static CloneOf <object> DeepCopy(this object source, Type targetType, Func <object> factory = null, int recurseCount = 0, bool?hideErrorsInPartialTrust = true) { if (recurseCount > 50) { throw new InvalidOperationException("Cannot clone an object graph greater than 50 objects in depth"); } var isPartialClone = false; //grab the type and create a new instance of that type var sourceType = targetType; var target = factory == null?CreateObject(targetType) : factory.Invoke(); //grab the properties var discoverableProperties = TypeFinder.CachedDiscoverableProperties(sourceType); //iterate over the properties and if it has a 'set' method assign it from the source TO the target foreach (var info in discoverableProperties) { // We don't check IsAssembly and IsFamily on the get method to ensure we don't try internal / private get accessors // because we rely on catching an exception instead - without comparing the PermissionSets of this code with the target // code IsAssembly and IsFamily don't give a clear picture of whether we can read it with reflection anyway // The GetMethod might have security parameters on it or might be internal. If security is tight // on the get method, it won't be returned, so check for null and double-check it's not internal var methodGetter = TypeFinder.DynamicMemberAccess.GetterDelegate(info); // We don't check !methodInfo.IsAssembly && !methodInfo.IsFamily here, instead leaving that to the try-catch // so that we can report back to the caller. If it was easier to check our PermissionSet with that of the type // we're looking at, I'd avoid a try-catch, but clarifying the PermissionSet requires full trust(!) - APN if (methodGetter != null) { try { var propertyValue = info.GetValue(source, null); var setter = TypeFinder.DynamicMemberAccess.SetterDelegate(info, true); SetValue(info, info.PropertyType, target, propertyValue, setter.Invoke, recurseCount); } catch (MemberAccessException) { if (hideErrorsInPartialTrust.HasValue && hideErrorsInPartialTrust.Value) { isPartialClone = true; continue; } throw; } } } // grab protected fields var discoverableFields = TypeFinder.CachedDiscoverableFields(sourceType); // Iterate over the properties to see if it is not readonly foreach (var fieldInfo in discoverableFields) { var localFieldInfoCopy = fieldInfo; try { var sourceValue = fieldInfo.GetValue(source); SetValue(fieldInfo, fieldInfo.FieldType, target, sourceValue, localFieldInfoCopy.SetValue, recurseCount); } catch (FieldAccessException) { if (hideErrorsInPartialTrust.HasValue && hideErrorsInPartialTrust.Value) { isPartialClone = true; continue; } throw; } } //return the new item return(new CloneOf <object>(isPartialClone, target)); }