Ejemplo n.º 1
0
        private async Task <object> AugmentInternal(
            object obj, Type type,
            Action <IState> addState,
            Action <AugmentationContext, object> configure,
            object configureState)
        {
            var tiw = TypeInfoResolver.ResolveTypeInfo(type);

            if (tiw.IsPrimitive)
            {
                return(obj);
            }

            var alwaysBuild       = tiw.IsWrapper || configure != null;
            var typeConfiguration = ResolveTypeConfiguration(tiw.Type, alwaysBuild);

            if (typeConfiguration == null && configure == null)
            {
                // No configuration
                return(obj);
            }

            var state = await CreateDictionaryAndAddStateAsync(addState, obj);

            var context = new AugmentationContext(obj, typeConfiguration, state);

            if (tiw.IsArray)
            {
                var asEnumerable = obj as IEnumerable;
                var list         = (obj as IList) != null ? new List <object>((obj as IList).Count) : new List <object>();
                Debug.Assert(asEnumerable != null, "asEnumerable != null");
                foreach (var item in asEnumerable)
                {
                    // We'll reuse the context.
                    context.Object = item;
                    list.Add(AugmentOne(obj, configure, configureState, tiw, context));
                }
                return(list);
            }
            else if (tiw.IsWrapper &&
                     ReflectionHelper.IsEnumerableOrArrayType((((AugmenterWrapper)obj).Object).GetType(), out var elementType))
            {
                context.EphemeralTypeConfiguration = ((AugmenterWrapper)obj).TypeConfiguration;
                obj = (((AugmenterWrapper)obj).Object);
                tiw = TypeInfoResolver.ResolveTypeInfo(elementType);
                var asEnumerable = obj as IEnumerable;
                var list         = (obj as IList) != null ? new List <object>((obj as IList).Count) : new List <object>();
                foreach (var item in asEnumerable)
                {
                    // We'll reuse the context.
                    context.Object = item;
                    list.Add(AugmentOne(obj, configure, configureState, tiw, context));
                }
                return(list);
            }
            else
            {
                return(AugmentOne(obj, configure, configureState, tiw, context));
            }
        }
        private static TypeConfiguration CreateConfigurationWithPropertiesOnly(Type baseType)
        {
            var tc = new TypeConfiguration(baseType);

            foreach (var pi in baseType.GetTypeInfo().DeclaredProperties)
            {
                tc.Properties.Add(
                    new APropertyInfo(pi, TypeInfoResolver.ResolveTypeInfo(pi.PropertyType), null));
            }
            return(tc);
        }
        private void BuildOne(Context context, Type type)
        {
            if (context.Current != null && context.Current.Built)
            {
                return;
            }

            if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
            {
                return;
            }

            var allTypes = ReflectionHelper.IncludeBaseTypesAndImplementedInterface(type);

            foreach (var implType in allTypes)
            {
                var tc = _all.FirstOrDefault(t => t.Type == implType);
                if (tc != null)
                {
                    context.EnsureCurrent();
                    context.AddBaseTypeConfiguration(tc);
                }
                else
                {
                    var scoped = context.CreateScoped(null, implType);
                    BuildOne(scoped, implType);
                    if (!scoped.Empty)
                    {
                        context.EnsureCurrent();
                        context.AddBaseTypeConfiguration(scoped.Current);
                    }
                    else
                    {
                        context.AddBaseTypeConfiguration(CreateConfigurationWithPropertiesOnly(implType));
                    }
                }
            }

            var properties = type.GetTypeInfo().DeclaredProperties;

            foreach (var p in properties)
            {
                if (p.GetMethod.IsStatic)
                {
                    continue;
                }

                var tiw = TypeInfoResolver.ResolveTypeInfo(p.PropertyType);

                if (tiw.IsPrimitive)
                {
                    context.Properties.Add(new APropertyInfo(p, tiw, null));
                }
                else if (tiw.Type == type)
                {
                    // Detect self referencing type.

                    context.EnsureCurrent();
                    context.Properties.Add(new APropertyInfo(p, tiw, context.Current));
                }
                else
                {
                    var nestedTypeConfiguration = _all.FirstOrDefault(c => c.Type == tiw.Type);
                    if (tiw.IsWrapper || (context.Current != null &&
                                          context.Current.NestedConfigurations.IsValueCreated &&
                                          context.Current.NestedConfigurations.Value.TryGetValue(p, out _)))
                    {
                        nestedTypeConfiguration = nestedTypeConfiguration ?? new TypeConfiguration(type);
                    }

                    var scoped = context.CreateScoped(
                        nestedTypeConfiguration,
                        tiw.Type);

                    BuildOne(scoped, tiw.Type);
                    if (!scoped.Empty)
                    {
                        context.EnsureCurrent();
                        context.Properties.Add(new APropertyInfo(p, tiw, scoped.Current));
                    }
                    else
                    {
                        context.Properties.Add(new APropertyInfo(p, tiw, null));
                    }
                }
            }

            if (!context.Empty)
            {
                context.EnsureCurrent();
                context.Current.Properties.AddRange(context.Properties);
            }
        }