/// <summary> /// Determines whether the specified actual type is type. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="actualType">The actual type.</param> /// <returns> /// <c>true</c> if the specified actual type is type; otherwise, <c>false</c>. /// </returns> public static bool IsType <T>(this Type actualType) { return(TypeFinder.IsTypeAssignableFrom <T>(actualType)); }
/// <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)); }
private static bool IsNotCloneable(MemberInfo info) { return(TypeFinder.IsTypeAssignableFrom <Delegate>(info.DeclaringType)); }
private static Func <object> GetObjectFactory(Type type) { if (type.IsInterface) { throw new InvalidOperationException("Cannot instantiate an interface ({0})".InvariantFormat(type.FullName)); } var isFullyTrusted = AppDomain.CurrentDomain.IsFullyTrusted; var constructor = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Where(x => x.GetParameters().Count() == 0 && (isFullyTrusted || (!isFullyTrusted && !x.IsSecurityCritical && !x.IsSecuritySafeCritical))) .FirstOrDefault(); if (constructor != null) { // This catch block is here because there are certain types of constructor that I can't grab via properties on ConstructorInfo // for example NullViewLocationCache is a sealed internal type with no constructor, yet a constructor is found using the above // method! try { return(() => constructor.Invoke(new object[0])); } catch (SecurityException ex) { LogSecurityException(type, isFullyTrusted, ex); } catch (MemberAccessException ex) { ThrowIfFullTrust(type, isFullyTrusted, ex); } } if (isFullyTrusted) { return(() => FormatterServices.GetUninitializedObject(type)); } // We're in partial trust, but haven't found a default constructor, so find the first constructor with nullable parameter types var nearestConstructor = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .OrderBy(x => x.GetParameters().Count()) .FirstOrDefault(); if (nearestConstructor != null) { var paramValues = nearestConstructor.GetParameters().Select(x => TypeFinder.IsImplicitValueType(x.ParameterType) ? x.ParameterType.GetDefaultValue() : CreateObject(x.ParameterType)).ToArray(); try { return(() => nearestConstructor.Invoke(paramValues)); } catch (SecurityException ex) { LogSecurityException(type, isFullyTrusted, ex); } catch (MemberAccessException ex) { ThrowIfFullTrust(type, isFullyTrusted, ex); } } throw new InvalidOperationException( "Cannot find a default constructor for {0}, and since this AppDomain is not fully trusted, also tried to find another constructor, but that failed too. Come to think of it, how do YOU make this object?".InvariantFormat(type.FullName)); }