| File: Forms\ExpressionMemberAccessor.cs | Web Access |
| Project: src\aspnetcore\src\Components\Web\src\Microsoft.AspNetCore.Components.Web.csproj (Microsoft.AspNetCore.Components.Web) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Concurrent; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq.Expressions; using System.Reflection; using Microsoft.AspNetCore.Components.HotReload; namespace Microsoft.AspNetCore.Components.Forms; internal static class ExpressionMemberAccessor { private static readonly ConcurrentDictionary<Expression, MemberInfo> _memberInfoCache = new(); private static readonly ConcurrentDictionary<MemberInfo, string> _displayNameCache = new(); static ExpressionMemberAccessor() { if (HotReloadManager.IsSupported) { HotReloadManager.Default.OnDeltaApplied += ClearCache; } } private static MemberInfo GetMemberInfo<TValue>(Expression<Func<TValue>> accessor) { ArgumentNullException.ThrowIfNull(accessor); return _memberInfoCache.GetOrAdd(accessor, static expr => { var lambdaExpression = (LambdaExpression)expr; var accessorBody = lambdaExpression.Body; if (accessorBody is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert && unaryExpression.Type == typeof(object)) { accessorBody = unaryExpression.Operand; } if (accessorBody is not MemberExpression memberExpression) { throw new ArgumentException( $"The provided expression contains a {accessorBody.GetType().Name} which is not supported. " + $"Only simple member accessors (fields, properties) of an object are supported."); } return memberExpression.Member; }); } public static string GetDisplayName(MemberInfo member) { ArgumentNullException.ThrowIfNull(member); return _displayNameCache.GetOrAdd(member, static m => { var displayAttribute = m.GetCustomAttribute<DisplayAttribute>(); if (displayAttribute is not null) { var name = displayAttribute.GetName(); if (name is not null) { return name; } } var displayNameAttribute = m.GetCustomAttribute<DisplayNameAttribute>(); if (displayNameAttribute?.DisplayName is not null) { return displayNameAttribute.DisplayName; } return m.Name; }); } public static string GetDisplayName<TValue>(Expression<Func<TValue>> accessor) { ArgumentNullException.ThrowIfNull(accessor); var member = GetMemberInfo(accessor); return GetDisplayName(member); } private static void ClearCache() { _memberInfoCache.Clear(); _displayNameCache.Clear(); } }