< Summary - PropertyGridHelpers Code Coverage

Information
Class: PropertyGridHelpers.PropertyDescriptors.LocalizedPropertyDescriptor
Assembly: PropertyGridHelpers
File(s): c:\agent\_work\9\s\Code\PropertyGridHelpers\PropertyDescriptors\LocalizedPropertyDescriptor.cs
Tag: PropertyGridHelpers Build_2025.7.15.1_#485
Line coverage
100%
Covered lines: 40
Uncovered lines: 0
Coverable lines: 40
Total lines: 168
Line coverage: 100%
Branch coverage
100%
Covered branches: 12
Total branches: 12
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBlocks covered Blocks not covered Branch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)--100%11100%
LocalizedPropertyDescriptor(...)20----
get_Category()--100%11100%
get_Description()--100%11100%
get_DisplayName()--100%11100%
GetLocalizedString<T>(...)230----
GetLocalizedString(...)--100%88100%
GetLocalizedString<T>(...)200----
GetResourceTypeFromProperty(...)190----
GetResourceTypeFromProperty(...)--100%44100%
GetResourceTypeFromProperty(...)180----
CanResetValue(...)20----
CanResetValue(...)--100%11100%
get_ComponentType()--100%11100%
GetValue(...)20----
GetValue(...)--100%11100%
get_IsReadOnly()--100%11100%
get_PropertyType()--100%11100%
ResetValue(...)20----
ResetValue(...)--100%11100%
SetValue(...)20----
SetValue(...)--100%11100%
ShouldSerializeValue(...)20----
ShouldSerializeValue(...)--100%11100%

File(s)

c:\agent\_work\9\s\Code\PropertyGridHelpers\PropertyDescriptors\LocalizedPropertyDescriptor.cs

#LineLine coverage
 1using PropertyGridHelpers.Attributes;
 2using System;
 3using System.ComponentModel;
 4using System.Globalization;
 5using System.Resources;
 6using System.Reflection;
 7
 8namespace PropertyGridHelpers.PropertyDescriptors
 9{
 10#if NET5_0_OR_GREATER
 11    /// <summary>
 12    /// A specialized <see cref="PropertyDescriptor"/> that supports localizing
 13    /// the category, description, and display name of a property based on
 14    /// resource attributes.
 15    /// </summary>
 16    /// <param name="baseProperty">The wrapped base property descriptor to decorate.</param>
 17    /// <remarks>
 18    /// This class is intended to wrap a standard property descriptor
 19    /// and provide localized versions of its metadata (category, description,
 20    /// display name) using associated <see cref="LocalizedTextAttribute"/>-derived
 21    /// attributes. At runtime, it retrieves localized strings from the
 22    /// appropriate resource files configured through the <see cref="ResourcePathAttribute"/>.
 23    /// </remarks>
 24    /// <seealso cref="PropertyDescriptor"/>
 10025    public class LocalizedPropertyDescriptor(PropertyDescriptor baseProperty) : PropertyDescriptor(baseProperty)
 26    {
 10027        private readonly PropertyDescriptor baseProperty = baseProperty;
 28#else
 29    /// <summary>
 30    /// A specialized <see cref="PropertyDescriptor"/> that supports localizing
 31    /// the category, description, and display name of a property based on
 32    /// resource attributes.
 33    /// </summary>
 34    /// <remarks>
 35    /// This class is intended to wrap a standard property descriptor
 36    /// and provide localized versions of its metadata (category, description,
 37    /// display name) using associated <see cref="LocalizedTextAttribute"/>-derived
 38    /// attributes. At runtime, it retrieves localized strings from the
 39    /// appropriate resource files configured through the <see cref="ResourcePathAttribute"/>.
 40    /// </remarks>
 41    /// <seealso cref="PropertyDescriptor"/>
 42    public class LocalizedPropertyDescriptor : PropertyDescriptor
 43    {
 44        private readonly PropertyDescriptor baseProperty;
 45
 46        /// <summary>
 47        /// Initializes a new instance of the <see cref="LocalizedPropertyDescriptor"/> class.
 48        /// </summary>
 49        /// <param name="baseProperty">The wrapped base property descriptor to decorate.</param>
 50        public LocalizedPropertyDescriptor(PropertyDescriptor baseProperty)
 1651            : base(baseProperty) =>
 1652            this.baseProperty = baseProperty;
 53#endif
 54        /// <summary>
 55        /// Gets the localized category name for this property.
 56        /// </summary>
 57        public override string Category =>
 2058            GetLocalizedString<LocalizedCategoryAttribute>(baseProperty.Category);
 59
 60        /// <summary>
 61        /// Gets the localized description for this property.
 62        /// </summary>
 63        public override string Description =>
 2064            GetLocalizedString<LocalizedDescriptionAttribute>(baseProperty.Description);
 65
 66        /// <summary>
 67        /// Gets the localized display name for this property.
 68        /// </summary>
 69        public override string DisplayName =>
 2070            GetLocalizedString<LocalizedDisplayNameAttribute>(baseProperty.DisplayName);
 71
 72        /// <summary>
 73        /// Retrieves a localized string from the specified attribute type, or
 74        /// returns the default string if no localization can be resolved.
 75        /// </summary>
 76        /// <typeparam name="T">
 77        /// The type of <see cref="LocalizedTextAttribute"/> to look for.
 78        /// </typeparam>
 79        /// <param name="defaultValue">The fallback value if localization fails.</param>
 80        /// <returns>
 81        /// The localized string if found; otherwise the default value.
 82        /// </returns>
 83        internal string GetLocalizedString<T>(string defaultValue) where T : LocalizedTextAttribute
 3284        {
 4085            if (baseProperty.Attributes[typeof(T)] is T localizedAttribute)
 3286            {
 4087                var resourcePath = string.Empty;
 4088                var resourceAssembly = GetResourceTypeFromProperty(ref resourcePath);
 89
 4090                if (resourceAssembly != null && !string.IsNullOrEmpty(resourcePath))
 2091                {
 2892                    var resourceManager = new ResourceManager(resourcePath, resourceAssembly);
 93                    try
 2094                    {
 2895                        return resourceManager.GetString(localizedAttribute.ResourceKey, CultureInfo.CurrentCulture) ?? 
 96                    }
 2097                    catch (MissingManifestResourceException)
 1298                    {
 2099                        return defaultValue;
 100                    }
 101                }
 20102            }
 103
 28104            return defaultValue;
 40105        }
 106
 107        /// <summary>
 108        /// Determines the resource assembly and fully qualified resource path
 109        /// used to resolve localized strings for this property.
 110        /// </summary>
 111        /// <param name="resourcePath">
 112        /// Outputs the computed resource path to the relevant resource file.
 113        /// </param>
 114        /// <returns>
 115        /// The assembly containing the resource type if found; otherwise null.
 116        /// </returns>
 117        internal Assembly GetResourceTypeFromProperty(ref string resourcePath)
 40118        {
 48119            ResourcePathAttribute resourcePathAttribute = null;
 120#if NET35
 121            var attributes = baseProperty.ComponentType.GetCustomAttributes(typeof(ResourcePathAttribute), false);
 122            if (attributes.Length > 0)
 123                resourcePathAttribute = (ResourcePathAttribute)attributes[0];
 124#else
 48125            resourcePathAttribute = baseProperty.ComponentType.GetCustomAttribute<ResourcePathAttribute>();
 126#endif
 60127            if (resourcePathAttribute == null) return null;
 128
 36129            resourcePath = $"{baseProperty.ComponentType.Assembly.GetName().Name}.{resourcePathAttribute.ResourcePath}";
 130
 36131            return !string.IsNullOrEmpty(resourcePathAttribute.ResourceAssembly) ?
 36132                   resourcePathAttribute.GetAssembly() :
 36133                   baseProperty.ComponentType.Assembly;
 40134        }
 135
 136        /// <inheritdoc/>
 137        public override bool CanResetValue(object component) =>
 20138            baseProperty.CanResetValue(component);
 139
 140        /// <inheritdoc/>
 141        public override Type ComponentType =>
 20142            baseProperty.ComponentType;
 143
 144        /// <inheritdoc/>
 145        public override object GetValue(object component) =>
 20146            baseProperty.GetValue(component);
 147
 148        /// <inheritdoc/>
 149        public override bool IsReadOnly =>
 20150            baseProperty.IsReadOnly;
 151
 152        /// <inheritdoc/>
 153        public override Type PropertyType =>
 20154            baseProperty.PropertyType;
 155
 156        /// <inheritdoc/>
 157        public override void ResetValue(object component) =>
 20158            baseProperty.ResetValue(component);
 159
 160        /// <inheritdoc/>
 161        public override void SetValue(object component, object value) =>
 20162            baseProperty.SetValue(component, value);
 163
 164        /// <inheritdoc/>
 165        public override bool ShouldSerializeValue(object component) =>
 20166            baseProperty.ShouldSerializeValue(component);
 167    }
 168}