/// <summary>
        ///     Cleanups up injectable properties. All injectable properties will be set to <c>null</c>.
        /// </summary>
        /// <remarks>
        ///     Since this method does not perform dependency validation
        ///     <see cref="InjectProperties" /> , <paramref name="cache" /> is used as read-only.
        ///     Calling <see cref="CleanupInjectableProperties" /> without call to <see cref="InjectProperties" /> on the same type
        ///     will incur performance penalty as list of properties will be evaluated every time.
        /// </remarks>
        /// <param name="kernel">Windsor kernel.</param>
        /// <param name="target">The target object to cleanup injectable properties.</param>
        /// <param name="cache">Injectable property descriptor cache.</param>
        public static void CleanupInjectableProperties([NotNull] this IKernel kernel, [NotNull] object target,
                                                       ITypePropertyDescriptorCache cache)
        {
            if (kernel == null)
            {
                throw new ArgumentNullException(nameof(kernel));
            }
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            Type type = target.GetType();
            // Cache miss expected only once per given type, so call Find() first to prevent extra closure allocation in GetOrAdd.
            TypePropertyDescriptor info = cache?.Find(type) ?? GetInjectableProperties(type, kernel, null);

            if (!info.HasProperties())
            {
                return;
            }

            // ReSharper disable once ForCanBeConvertedToForeach
            for (var i = 0; i < info.Properties.Length; i++)
            {
                info.Properties[i].SetValue(target, null, null);
            }
        }
        public void GetOrAdd_Should_AddMissingItemToCache()
        {
            Type type       = GetType();
            var  descriptor = new TypePropertyDescriptor(type, null);

            _cache.GetOrAdd(type, t => descriptor).Should().BeSameAs(descriptor);
        }
Example #3
0
        /// <summary>
        ///     Returns the properties of the current object that make up the object's signature.
        /// </summary>
        public virtual PropertyInfo[] GetSignatureProperties()
        {
            Type type = GetTypeUnproxied();

            // Since data won't be in cache on first request only, use .GetOrAdd as second attempt to prevent allocation of extra lambda object.
            TypePropertyDescriptor descriptor = signaturePropertiesCache.Find(type) ?? GetOrAdd(type);

            return(descriptor.Properties);
        }
        private static TypePropertyDescriptor GetInjectableProperties(IKernel kernel, ITypePropertyDescriptorCache cache,
                                                                      Action <PropertyInfo, ComponentModel> validatePropertyRegistration, Type type)
        {
            // Cache miss expected only once per given type, so call Find() first to prevent extra closure allocation in GetOrAdd.
            TypePropertyDescriptor info = cache != null
                ? cache.Find(type) ?? GetOrAdd(kernel, cache, type, validatePropertyRegistration)
                : GetInjectableProperties(type, kernel, validatePropertyRegistration);

            return(info);
        }
        /// <summary>
        ///     Injects dependencies into properties.
        /// </summary>
        /// <param name="kernel">Windsor kernel</param>
        /// <param name="target">The target object to inject properties.</param>
        /// <param name="cache">Injectable property descriptor cache.</param>
        /// <param name="validatePropertyRegistration">
        ///     Callback to validate property dependency to be injected. Must throw
        ///     exception in case of failure.
        /// </param>
        /// <exception cref="ComponentActivatorException"></exception>
        /// <exception cref="ArgumentNullException"><paramref name="target" /> is <see langword="null" />.</exception>
        public static void InjectProperties([NotNull] this IKernel kernel, [NotNull] object target,
                                            [CanBeNull] ITypePropertyDescriptorCache cache,
                                            Action <PropertyInfo, ComponentModel> validatePropertyRegistration = null)
        {
            if (kernel == null)
            {
                throw new ArgumentNullException(nameof(kernel));
            }
            if (target == null)
            {
                throw new ArgumentNullException(nameof(target));
            }

            Type type = target.GetType();
            TypePropertyDescriptor info = GetInjectableProperties(kernel, cache, validatePropertyRegistration, type);

            if (!info.HasProperties())
            {
                return;
            }

            // ReSharper disable once ForCanBeConvertedToForeach
            for (var i = 0; i < info.Properties.Length; i++)
            {
                PropertyInfo injectableProperty = info.Properties[i];
                object       val = kernel.Resolve(injectableProperty.PropertyType);
                try
                {
                    injectableProperty.SetValue(target, val, null);
                }
                catch (Exception ex)
                {
                    string message =
                        $"Error injecting property {injectableProperty.Name} on type {type.FullName}, See inner exception for more information.";
                    throw new ComponentActivatorException(message, ex, null);
                }
            }
        }
Example #6
0
        private CustomTypeDescriptor(Type type, bool isAnonymousClass, MemberInfo[] members, string[] names)
        {
            if (type == null) 
                throw new ArgumentNullException("type");

            //
            // No members supplied? Get all public, instance-level fields and 
            // properties of the type that are not marked with the JsonIgnore
            // attribute.
            //
            
            if (members == null)
            {
                const BindingFlags bindings = BindingFlags.Instance | BindingFlags.Public;
                FieldInfo[] fields = type.GetFields(bindings);
                PropertyInfo[] properties = type.GetProperties(bindings);
                
                //
                // Filter out members marked with JsonIgnore attribute.
                //
                
                ArrayList memberList = new ArrayList(fields.Length + properties.Length);
                memberList.AddRange(fields);
                memberList.AddRange(properties);

                for (int i = 0; i < memberList.Count; i++)
                {
                    MemberInfo member = (MemberInfo) memberList[i];
                    
                    if (!member.IsDefined(typeof(JsonIgnoreAttribute), true))
                        continue;
                    
                    memberList.RemoveAt(i--);
                }
                
                members = (MemberInfo[]) memberList.ToArray(typeof(MemberInfo));
            }
                        
            PropertyDescriptorCollection logicalProperties = new PropertyDescriptorCollection(null);
            
            int index = 0;
            
            foreach (MemberInfo member in members)
            {
                FieldInfo field = member as FieldInfo;
                string name = names != null && index < names.Length ? names[index] : null;
                TypeMemberDescriptor descriptor = null;

                if (field != null)
                {
                    //
                    // Add public fields that are not read-only and not 
                    // constant literals.
                    //
            
                    if (field.DeclaringType != type && field.ReflectedType != type)
                        throw new ArgumentException(null, "members");
                
                    if (!field.IsInitOnly && !field.IsLiteral)
                        descriptor = new TypeFieldDescriptor(field, name);
                }
                else
                {
                    PropertyInfo property = member as PropertyInfo;
                    
                    if (property == null)
                        throw new ArgumentException(null, "members");
                    
                    //
                    // Add public properties that can be read and modified.
                    // If property is read-only yet has the JsonExport 
                    // attribute applied then include it anyhow (assuming
                    // that the type author probably has customizations
                    // that know how to deal with the sceanrio more 
                    // accurately). What's more, if the type is anonymous 
                    // then the rule that the proerty must be writeable is
                    // also bypassed.
                    //

                    if (property.DeclaringType != type && property.ReflectedType != type)
                        throw new ArgumentException(null, "members");

                    if ((property.CanRead) &&
                        (isAnonymousClass || property.CanWrite || property.IsDefined(typeof(JsonExportAttribute), true)) &&
                        property.GetIndexParameters().Length == 0)
                    {
                        //
                        // Properties of an anonymous class will always use 
                        // their original property name so that no 
                        // transformation (like auto camel-casing) is 
                        // applied. The rationale for the exception here is
                        // that since the user does not have a chance to
                        // decorate properties of an anonymous class with
                        // attributes, there is no way an overriding policy
                        // can be implemented.
                        //

                        descriptor = new TypePropertyDescriptor(property, 
                            isAnonymousClass ? Mask.EmptyString(name, property.Name) : name);
                    }
                }
                
                if (descriptor != null)
                {
                    descriptor.ApplyCustomizations();
                    logicalProperties.Add(descriptor);
                }
                
                index++;
            }
                
            _properties = logicalProperties;
        }
        private CustomTypeDescriptor(Type type, bool isAnonymousClass, MemberInfo[] members, string[] names)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            //
            // No members supplied? Get all public, instance-level fields and
            // properties of the type that are not marked with the JsonIgnore
            // attribute.
            //

            if (members == null)
            {
                const BindingFlags bindings   = BindingFlags.Instance | BindingFlags.Public;
                FieldInfo[]        fields     = type.GetFields(bindings);
                PropertyInfo[]     properties = type.GetProperties(bindings);

                //
                // Filter out members marked with JsonIgnore attribute.
                //

                ArrayList memberList = new ArrayList(fields.Length + properties.Length);
                memberList.AddRange(fields);
                memberList.AddRange(properties);

                for (int i = 0; i < memberList.Count; i++)
                {
                    MemberInfo member = (MemberInfo)memberList[i];

                    if (!member.IsDefined(typeof(JsonIgnoreAttribute), true))
                    {
                        continue;
                    }

                    memberList.RemoveAt(i--);
                }

                members = (MemberInfo[])memberList.ToArray(typeof(MemberInfo));
            }

            PropertyDescriptorCollection logicalProperties = new PropertyDescriptorCollection(null);

            int index = 0;

            foreach (MemberInfo member in members)
            {
                FieldInfo            field      = member as FieldInfo;
                string               name       = names != null && index < names.Length ? names[index] : null;
                TypeMemberDescriptor descriptor = null;

                if (field != null)
                {
                    //
                    // Add public fields that are not read-only and not
                    // constant literals.
                    //

                    if (field.DeclaringType != type && field.ReflectedType != type)
                    {
                        throw new ArgumentException(null, "members");
                    }

                    if (!field.IsInitOnly && !field.IsLiteral)
                    {
                        descriptor = new TypeFieldDescriptor(field, name);
                    }
                }
                else
                {
                    PropertyInfo property = member as PropertyInfo;

                    if (property == null)
                    {
                        throw new ArgumentException(null, "members");
                    }

                    //
                    // Add public properties that can be read and modified.
                    // If property is read-only yet has the JsonExport
                    // attribute applied then include it anyhow (assuming
                    // that the type author probably has customizations
                    // that know how to deal with the sceanrio more
                    // accurately). What's more, if the type is anonymous
                    // then the rule that the proerty must be writeable is
                    // also bypassed.
                    //

                    if (property.DeclaringType != type && property.ReflectedType != type)
                    {
                        throw new ArgumentException(null, "members");
                    }

                    if ((property.CanRead) &&
                        (isAnonymousClass || property.CanWrite || property.IsDefined(typeof(JsonExportAttribute), true)) &&
                        property.GetIndexParameters().Length == 0)
                    {
                        //
                        // Properties of an anonymous class will always use
                        // their original property name so that no
                        // transformation (like auto camel-casing) is
                        // applied. The rationale for the exception here is
                        // that since the user does not have a chance to
                        // decorate properties of an anonymous class with
                        // attributes, there is no way an overriding policy
                        // can be implemented.
                        //

                        descriptor = new TypePropertyDescriptor(property,
                                                                isAnonymousClass ? Mask.EmptyString(name, property.Name) : name);
                    }
                }

                if (descriptor != null)
                {
                    descriptor.ApplyCustomizations();
                    logicalProperties.Add(descriptor);
                }

                index++;
            }

            _properties = logicalProperties;
        }
 public void GetOrAdd_Should_AddMissingItemToCache()
 {
     Type type = GetType();
     var descriptor = new TypePropertyDescriptor(type, null);
     _cache.GetOrAdd(type, t => descriptor).Should().BeSameAs(descriptor);
 }