File: System\Linq\Expressions\IArgumentProvider.cs
Web Access
Project: src\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;
        }
    }
}