From 91428a6b0bf4ee159202c2a85e6ba3cd4d975271 Mon Sep 17 00:00:00 2001 From: n9 Date: Fri, 27 Sep 2024 09:51:38 +0200 Subject: [PATCH] Extract PropertiesTypeInspector from ReadablePropertiesTypeInspector and WritablePropertiesTypeInspector + add virtual method CreateProperty to PropertiesTypeInspector and PropertyInfo to ReflectionPropertyDescriptor for #984 --- .../TypeInspectors/PropertiesTypeInspector.cs | 113 ++++++++++++++++++ .../ReadablePropertiesTypeInspector.cs | 69 +---------- .../WritablePropertiesTypeInspector.cs | 68 +---------- 3 files changed, 117 insertions(+), 133 deletions(-) create mode 100644 YamlDotNet/Serialization/TypeInspectors/PropertiesTypeInspector.cs diff --git a/YamlDotNet/Serialization/TypeInspectors/PropertiesTypeInspector.cs b/YamlDotNet/Serialization/TypeInspectors/PropertiesTypeInspector.cs new file mode 100644 index 00000000..371e18c9 --- /dev/null +++ b/YamlDotNet/Serialization/TypeInspectors/PropertiesTypeInspector.cs @@ -0,0 +1,113 @@ +// This file is part of YamlDotNet - A .NET library for YAML. +// Copyright (c) Antoine Aubry and contributors +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using YamlDotNet.Core; + +namespace YamlDotNet.Serialization.TypeInspectors +{ + public class PropertiesTypeInspector : ReflectionTypeInspector + { + private readonly ITypeResolver typeResolver; + private readonly bool includeNonPublicProperties; + + public PropertiesTypeInspector(ITypeResolver typeResolver) + : this(typeResolver, false) + { + } + + public PropertiesTypeInspector(ITypeResolver typeResolver, bool includeNonPublicProperties) + { + this.typeResolver = typeResolver ?? throw new ArgumentNullException(nameof(typeResolver)); + this.includeNonPublicProperties = includeNonPublicProperties; + } + + protected virtual bool IsValidProperty(PropertyInfo property) + => true; + + protected virtual ReflectionPropertyDescriptor CreateProperty(PropertyInfo property) + => new ReflectionPropertyDescriptor(property, typeResolver); + + public override IEnumerable GetProperties(Type type, object? container) + { + return type + .GetProperties(includeNonPublicProperties) + .Where(IsValidProperty) + .Select(p => (IPropertyDescriptor)CreateProperty(p)); + } + + protected class ReflectionPropertyDescriptor : IPropertyDescriptor + { + private readonly PropertyInfo propertyInfo; + private readonly ITypeResolver typeResolver; + + public ReflectionPropertyDescriptor(PropertyInfo propertyInfo, ITypeResolver typeResolver) + { + this.propertyInfo = propertyInfo ?? throw new ArgumentNullException(nameof(propertyInfo)); + this.typeResolver = typeResolver ?? throw new ArgumentNullException(nameof(typeResolver)); + ScalarStyle = ScalarStyle.Any; + var converterAttribute = propertyInfo.GetCustomAttribute(); + if (converterAttribute != null) + { + ConverterType = converterAttribute.ConverterType; + } + } + + public string Name => propertyInfo.Name; + public bool Required { get => propertyInfo.IsRequired(); } + public Type Type => propertyInfo.PropertyType; + public Type? TypeOverride { get; set; } + public Type? ConverterType { get; set; } + + public bool AllowNulls { get => propertyInfo.AcceptsNull(); } + + public int Order { get; set; } + public bool CanWrite => propertyInfo.CanWrite; + public ScalarStyle ScalarStyle { get; set; } + + public PropertyInfo PropertyInfo => propertyInfo; + + public void Write(object target, object? value) + { + propertyInfo.SetValue(target, value, null); + } + + public T? GetCustomAttribute() where T : Attribute + { + var attributes = propertyInfo.GetAllCustomAttributes(); + return (T?)attributes.FirstOrDefault(); + } + + public IObjectDescriptor Read(object target) + { + var propertyValue = propertyInfo.ReadValue(target); + var actualType = TypeOverride ?? typeResolver.Resolve(Type, propertyValue); + return new ObjectDescriptor(propertyValue, actualType, Type, ScalarStyle); + } + } + } + +} diff --git a/YamlDotNet/Serialization/TypeInspectors/ReadablePropertiesTypeInspector.cs b/YamlDotNet/Serialization/TypeInspectors/ReadablePropertiesTypeInspector.cs index e578d522..be82f3fc 100644 --- a/YamlDotNet/Serialization/TypeInspectors/ReadablePropertiesTypeInspector.cs +++ b/YamlDotNet/Serialization/TypeInspectors/ReadablePropertiesTypeInspector.cs @@ -30,82 +30,17 @@ namespace YamlDotNet.Serialization.TypeInspectors /// /// Returns the properties of a type that are readable. /// - public class ReadablePropertiesTypeInspector : ReflectionTypeInspector + public class ReadablePropertiesTypeInspector(ITypeResolver typeResolver, bool includeNonPublicProperties) : PropertiesTypeInspector(typeResolver, includeNonPublicProperties) { - private readonly ITypeResolver typeResolver; - private readonly bool includeNonPublicProperties; - public ReadablePropertiesTypeInspector(ITypeResolver typeResolver) : this(typeResolver, false) { } - public ReadablePropertiesTypeInspector(ITypeResolver typeResolver, bool includeNonPublicProperties) - { - this.typeResolver = typeResolver ?? throw new ArgumentNullException(nameof(typeResolver)); - this.includeNonPublicProperties = includeNonPublicProperties; - } - - private static bool IsValidProperty(PropertyInfo property) + protected override bool IsValidProperty(PropertyInfo property) { return property.CanRead && property.GetGetMethod(true)!.GetParameters().Length == 0; } - - public override IEnumerable GetProperties(Type type, object? container) - { - return type - .GetProperties(includeNonPublicProperties) - .Where(IsValidProperty) - .Select(p => (IPropertyDescriptor)new ReflectionPropertyDescriptor(p, typeResolver)); - } - - protected class ReflectionPropertyDescriptor : IPropertyDescriptor - { - private readonly PropertyInfo propertyInfo; - private readonly ITypeResolver typeResolver; - - public ReflectionPropertyDescriptor(PropertyInfo propertyInfo, ITypeResolver typeResolver) - { - this.propertyInfo = propertyInfo ?? throw new ArgumentNullException(nameof(propertyInfo)); - this.typeResolver = typeResolver ?? throw new ArgumentNullException(nameof(typeResolver)); - ScalarStyle = ScalarStyle.Any; - var converterAttribute = propertyInfo.GetCustomAttribute(); - if (converterAttribute != null) - { - ConverterType = converterAttribute.ConverterType; - } - } - - public string Name => propertyInfo.Name; - public bool Required { get => propertyInfo.IsRequired(); } - public Type Type => propertyInfo.PropertyType; - public Type? TypeOverride { get; set; } - public Type? ConverterType { get; set; } - - public bool AllowNulls { get => propertyInfo.AcceptsNull(); } - - public int Order { get; set; } - public bool CanWrite => propertyInfo.CanWrite; - public ScalarStyle ScalarStyle { get; set; } - - public void Write(object target, object? value) - { - propertyInfo.SetValue(target, value, null); - } - - public T? GetCustomAttribute() where T : Attribute - { - var attributes = propertyInfo.GetAllCustomAttributes(); - return (T?)attributes.FirstOrDefault(); - } - - public IObjectDescriptor Read(object target) - { - var propertyValue = propertyInfo.ReadValue(target); - var actualType = TypeOverride ?? typeResolver.Resolve(Type, propertyValue); - return new ObjectDescriptor(propertyValue, actualType, Type, ScalarStyle); - } - } } } diff --git a/YamlDotNet/Serialization/TypeInspectors/WritablePropertiesTypeInspector.cs b/YamlDotNet/Serialization/TypeInspectors/WritablePropertiesTypeInspector.cs index 2b9a6897..7c80c58e 100644 --- a/YamlDotNet/Serialization/TypeInspectors/WritablePropertiesTypeInspector.cs +++ b/YamlDotNet/Serialization/TypeInspectors/WritablePropertiesTypeInspector.cs @@ -30,81 +30,17 @@ namespace YamlDotNet.Serialization.TypeInspectors /// /// Returns the properties of a type that are writable. /// - public class WritablePropertiesTypeInspector : ReflectionTypeInspector + public class WritablePropertiesTypeInspector(ITypeResolver typeResolver, bool includeNonPublicProperties) : PropertiesTypeInspector(typeResolver, includeNonPublicProperties) { - private readonly ITypeResolver typeResolver; - private readonly bool includeNonPublicProperties; - public WritablePropertiesTypeInspector(ITypeResolver typeResolver) : this(typeResolver, false) { } - public WritablePropertiesTypeInspector(ITypeResolver typeResolver, bool includeNonPublicProperties) - { - this.typeResolver = typeResolver ?? throw new ArgumentNullException(nameof(typeResolver)); - this.includeNonPublicProperties = includeNonPublicProperties; - } - - private static bool IsValidProperty(PropertyInfo property) + protected override bool IsValidProperty(PropertyInfo property) { return property.CanWrite && property.GetSetMethod(true)!.GetParameters().Length == 1; } - - public override IEnumerable GetProperties(Type type, object? container) - { - return type - .GetProperties(includeNonPublicProperties) - .Where(IsValidProperty) - .Select(p => (IPropertyDescriptor)new ReflectionPropertyDescriptor(p, typeResolver)) - .ToArray(); - } - - protected class ReflectionPropertyDescriptor : IPropertyDescriptor - { - private readonly PropertyInfo propertyInfo; - private readonly ITypeResolver typeResolver; - - public ReflectionPropertyDescriptor(PropertyInfo propertyInfo, ITypeResolver typeResolver) - { - this.propertyInfo = propertyInfo ?? throw new ArgumentNullException(nameof(propertyInfo)); - this.typeResolver = typeResolver ?? throw new ArgumentNullException(nameof(typeResolver)); - ScalarStyle = ScalarStyle.Any; - var converterAttribute = propertyInfo.GetCustomAttribute(); - if (converterAttribute != null) - { - ConverterType = converterAttribute.ConverterType; - } - } - - public string Name => propertyInfo.Name; - public bool Required { get => propertyInfo.IsRequired(); } - public Type Type => propertyInfo.PropertyType; - public Type? TypeOverride { get; set; } - public Type? ConverterType { get; set; } - public bool AllowNulls { get => propertyInfo.AcceptsNull(); } - public int Order { get; set; } - public bool CanWrite => propertyInfo.CanWrite; - public ScalarStyle ScalarStyle { get; set; } - - public void Write(object target, object? value) - { - propertyInfo.SetValue(target, value, null); - } - - public T? GetCustomAttribute() where T : Attribute - { - var attributes = propertyInfo.GetAllCustomAttributes(); - return (T?)attributes.FirstOrDefault(); - } - - public IObjectDescriptor Read(object target) - { - var propertyValue = propertyInfo.ReadValue(target); - var actualType = TypeOverride ?? typeResolver.Resolve(Type, propertyValue); - return new ObjectDescriptor(propertyValue, actualType, Type, ScalarStyle); - } - } } }