예제 #1
0
 /// <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));
 }
예제 #2
0
        /// <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));
        }
예제 #3
0
 private static bool IsNotCloneable(MemberInfo info)
 {
     return(TypeFinder.IsTypeAssignableFrom <Delegate>(info.DeclaringType));
 }
예제 #4
0
        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));
        }