File: MemberExpressionCacheKey.cs
Web Access
Project: src\src\Mvc\Mvc.ViewFeatures\src\Microsoft.AspNetCore.Mvc.ViewFeatures.csproj (Microsoft.AspNetCore.Mvc.ViewFeatures)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Linq.Expressions;
using System.Reflection;
 
namespace Microsoft.AspNetCore.Mvc.ViewFeatures;
 
internal readonly struct MemberExpressionCacheKey
{
    public MemberExpressionCacheKey(Type modelType, MemberExpression memberExpression)
    {
        ModelType = modelType;
        MemberExpression = memberExpression;
        Members = null;
    }
 
    public MemberExpressionCacheKey(Type modelType, MemberInfo[] members)
    {
        ModelType = modelType;
        Members = members;
        MemberExpression = null;
    }
 
    // We want to avoid caching a MemberExpression since it has references to other instances in the expression tree.
    // We instead store it as a series of MemberInfo items that comprise of the MemberExpression going from right-most
    // expression to left.
    public MemberExpressionCacheKey MakeCacheable()
    {
        var members = new List<MemberInfo>();
        foreach (var member in this)
        {
            members.Add(member);
        }
 
        return new MemberExpressionCacheKey(ModelType, members.ToArray());
    }
 
    public MemberExpression MemberExpression { get; }
 
    public Type ModelType { get; }
 
    public MemberInfo[] Members { get; }
 
    public Enumerator GetEnumerator() => new Enumerator(this);
 
    public struct Enumerator
    {
        private readonly MemberInfo[] _members;
        private int _index;
        private MemberExpression _memberExpression;
 
        public Enumerator(in MemberExpressionCacheKey key)
        {
            Current = null;
            _members = key.Members;
            _memberExpression = key.MemberExpression;
            _index = -1;
        }
 
        public MemberInfo Current { get; private set; }
 
        public bool MoveNext()
        {
            if (_members != null)
            {
                _index++;
                if (_index >= _members.Length)
                {
                    return false;
                }
 
                Current = _members[_index];
                return true;
            }
 
            if (_memberExpression == null)
            {
                return false;
            }
 
            Current = _memberExpression.Member;
            _memberExpression = _memberExpression.Expression as MemberExpression;
            return true;
        }
    }
}