| File: System\Linq\Expressions\IArgumentProvider.cs | Web Access |
| Project: src\runtime\src\libraries\System.Linq.Expressions\src\System.Linq.Expressions.csproj (System.Linq.Expressions) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace System.Linq.Expressions { /// <summary> /// Interface for accessing the arguments of multiple tree nodes (<see cref="IDynamicExpression"/>, /// <see cref="ElementInit"/>, <see cref="MethodCallExpression"/>, <see cref="InvocationExpression"/>, /// <see cref="NewExpression"/>, and <see cref="IndexExpression"/>). /// </summary> /// <remarks> /// This enables two optimizations which reduce the size of the trees. The first is it enables /// the nodes to hold onto an <see cref="Collections.Generic.IList{T}"/> instead of a /// <see cref="Collections.ObjectModel.ReadOnlyCollection{T}"/>. This saves the cost of allocating /// the read-only collection for each node. The second is that it enables specialized subclasses to be /// created which hold onto a specific number of arguments. These nodes can therefore avoid allocating /// both a <see cref="Collections.ObjectModel.ReadOnlyCollection{T}"/> and an array for storing their /// elements, thus saving 32 bytes per node. This technique is used by various nodes including /// <see cref="BlockExpression"/>, <see cref="InvocationExpression"/>, <see cref="MethodCallExpression"/>. /// /// Meanwhile the nodes can expose properties of <see cref="Collections.ObjectModel.ReadOnlyCollection{T}"/>s. /// They do this by re-using one field for storing both the array or an element that would normally be stored /// in the array. /// /// For the array case the collection is typed to <see cref="Collections.Generic.IList{T}"/> instead /// of <see cref="Collections.ObjectModel.ReadOnlyCollection{T}"/>. When the node is initially constructed /// it is an array. When utilities in this library access the arguments it uses this interface. If a user /// accesses the property the array is promoted to a <see cref="Collections.ObjectModel.ReadOnlyCollection{T}"/>. /// /// For the object case we store the first argument in a field typed to <see cref="object"/> and when /// the node is initially constructed this holds directly onto the <see cref="Expression"/> of the /// first argument. When utilities in this library access the arguments it again uses this interface /// and the accessor for the first argument uses <see cref="System.Dynamic.Utils.ExpressionUtils.ReturnObject{T}"/> to return the object /// which handles the <see cref="Expression"/> or <see cref="Collections.ObjectModel.ReadOnlyCollection{T}"/> case. /// When the user accesses the property the object field is updated to hold directly onto the /// <see cref="Collections.ObjectModel.ReadOnlyCollection{T}"/>. /// /// It is important that <see cref="Expression"/> properties consistently return the same /// <see cref="Collections.ObjectModel.ReadOnlyCollection{T}"/> otherwise the rewriter used by expression /// visitors will be broken and it would be a breaking change from LINQ v1. The problem is that currently /// users can rely on object identity to tell if the node has changed. Storing the read-only collection in /// an overloaded field enables us to both reduce memory usage as well as maintain compatibility and an /// easy to use external API. /// </remarks> public interface IArgumentProvider { /// <summary> /// Gets the argument expression with the specified <paramref name="index"/>. /// </summary> /// <param name="index">The index of the argument expression to get.</param> /// <returns>The expression representing the argument at the specified <paramref name="index"/>.</returns> Expression GetArgument(int index); /// <summary> /// Gets the number of argument expressions of the node. /// </summary> int ArgumentCount { get; } } }