/// <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); }
/// <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); } } }
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; }