#if NET20 || NET30 || !NET_4_6
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Reflection;
using LinqInternal.Collections;
using LinqInternal.Core;
namespace System.Linq.Expressions.Reimplement
{
///
/// Represents an expression that applies a delegate or lambda expression to a list of argument expressions.
///
[DebuggerTypeProxy(typeof(InvocationExpressionProxy))]
public sealed class InvocationExpression : Expression, IArgumentProvider
{
private IList _arguments;
private readonly Expression _lambda;
private readonly Type _returnType;
internal InvocationExpression(Expression lambda, IList arguments, Type returnType)
{
_lambda = lambda;
_arguments = arguments;
_returnType = returnType;
}
///
/// Gets the static type of the expression that this represents.
///
/// The that represents the static type of the expression.
public override Type Type
{
get { return _returnType; }
}
///
/// Returns the node type of this Expression. Extension nodes should return
/// ExpressionType.Extension when overriding this method.
///
/// The of the expression.
public override ExpressionType NodeType
{
get { return ExpressionType.Invoke; }
}
///
/// Gets the delegate or lambda expression to be applied.
///
public Expression Expression
{
get { return _lambda; }
}
///
/// Gets the arguments that the delegate or lambda expression is applied to.
///
public ReadOnlyCollection Arguments
{
get { return ReturnReadOnly(ref _arguments); }
}
///
/// Creates a new expression that is like this one, but using the
/// supplied children. If all of the children are the same, it will
/// return this expression.
///
/// The property of the result.
/// The property of the result.
/// This expression if no children changed, or an expression with the updated children.
public InvocationExpression Update(Expression expression, IEnumerable arguments)
{
if (expression == Expression && arguments == Arguments)
{
return this;
}
return Invoke(expression, arguments);
}
public Expression GetArgument(int index)
{
return _arguments[index];
}
public int ArgumentCount
{
get { return _arguments.Count; }
}
protected internal override Expression Accept(ExpressionVisitor visitor)
{
return visitor.VisitInvocation(this);
}
internal InvocationExpression Rewrite(Expression lambda, Expression[] arguments)
{
Debug.Assert(lambda != null);
Debug.Assert(arguments == null || arguments.Length == _arguments.Count);
return Invoke(lambda, arguments ?? _arguments);
}
internal LambdaExpression LambdaOperand
{
get
{
return (_lambda.NodeType == ExpressionType.Quote)
? (LambdaExpression)((UnaryExpression)_lambda).Operand
: (_lambda as LambdaExpression);
}
}
}
public partial class Expression
{
///
///Creates an that
///applies a delegate or lambda expression to a list of argument expressions.
///
///
///An that
///applies the specified delegate or lambda expression to the provided arguments.
///
///
///An that represents the delegate
///or lambda expression to be applied.
///
///
///An array of objects
///that represent the arguments that the delegate or lambda expression is applied to.
///
///
/// is null.
///
///.Type does not represent a delegate type or an .-or-The property of an element of is not assignable to the type of the corresponding parameter of the delegate represented by .
///
/// does not contain the same number of elements as the list of parameters for the delegate represented by .
public static InvocationExpression Invoke(Expression expression, params Expression[] arguments)
{
return Invoke(expression, (IEnumerable)arguments);
}
///
///Creates an that
///applies a delegate or lambda expression to a list of argument expressions.
///
///
///An that
///applies the specified delegate or lambda expression to the provided arguments.
///
///
///An that represents the delegate
///or lambda expression to be applied.
///
///
///An of objects
///that represent the arguments that the delegate or lambda expression is applied to.
///
///
/// is null.
///
///.Type does not represent a delegate type or an .-or-The property of an element of is not assignable to the type of the corresponding parameter of the delegate represented by .
///
/// does not contain the same number of elements as the list of parameters for the delegate represented by .
public static InvocationExpression Invoke(Expression expression, IEnumerable arguments)
{
RequiresCanRead(expression, "expression");
var args = arguments.ToReadOnly();
var mi = GetInvokeMethod(expression);
ValidateArgumentTypes(mi, ExpressionType.Invoke, ref args);
return new InvocationExpression(expression, args, mi.ReturnType);
}
///
/// Gets the delegate's Invoke method; used by InvocationExpression.
///
/// The expression to be invoked.
internal static MethodInfo GetInvokeMethod(Expression expression)
{
var delegateType = expression.Type;
if (!expression.Type.IsSubclassOf(typeof(MulticastDelegate)))
{
var exprType = TypeHelper.FindGenericType(typeof(Expression<>), expression.Type);
if (exprType == null)
{
throw Error.ExpressionTypeNotInvocable(expression.Type);
}
delegateType = exprType.GetGenericArguments()[0];
}
return delegateType.GetMethod("Invoke");
}
}
}
#endif