You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -0,0 +1,148 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
#if CLR2
|
||||
using Microsoft.Scripting.Ast;
|
||||
#else
|
||||
using System.Linq.Expressions;
|
||||
#endif
|
||||
|
||||
using System.Dynamic.Utils;
|
||||
|
||||
namespace System.Dynamic {
|
||||
/// <summary>
|
||||
/// Represents the binary dynamic operation at the call site, providing the binding semantic and the details about the operation.
|
||||
/// </summary>
|
||||
public abstract class BinaryOperationBinder : DynamicMetaObjectBinder {
|
||||
private ExpressionType _operation;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BinaryOperationBinder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="operation">The binary operation kind.</param>
|
||||
protected BinaryOperationBinder(ExpressionType operation) {
|
||||
ContractUtils.Requires(OperationIsValid(operation), "operation");
|
||||
_operation = operation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result type of the operation.
|
||||
/// </summary>
|
||||
public override sealed Type ReturnType {
|
||||
get { return typeof(object); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The binary operation kind.
|
||||
/// </summary>
|
||||
public ExpressionType Operation {
|
||||
get {
|
||||
return _operation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the binary dynamic operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic binary operation.</param>
|
||||
/// <param name="arg">The right hand side operand of the dynamic binary operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg) {
|
||||
return FallbackBinaryOperation(target, arg, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in the derived class, performs the binding of the binary dynamic operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic binary operation.</param>
|
||||
/// <param name="arg">The right hand side operand of the dynamic binary operation.</param>
|
||||
/// <param name="errorSuggestion">The binding result in case the binding fails, or null.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public abstract DynamicMetaObject FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion);
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic binary operation.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic operation.</param>
|
||||
/// <param name="args">An array of arguments of the dynamic operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public sealed override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(target, "target");
|
||||
ContractUtils.RequiresNotNull(args, "args");
|
||||
ContractUtils.Requires(args.Length == 1, "args");
|
||||
|
||||
var arg0 = args[0];
|
||||
ContractUtils.RequiresNotNull(arg0, "args");
|
||||
|
||||
return target.BindBinaryOperation(this, arg0);
|
||||
}
|
||||
|
||||
// this is a standard DynamicMetaObjectBinder
|
||||
internal override sealed bool IsStandardBinder {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
|
||||
internal static bool OperationIsValid(ExpressionType operation) {
|
||||
switch (operation) {
|
||||
#region Generated Binary Operation Binder Validator
|
||||
|
||||
// *** BEGIN GENERATED CODE ***
|
||||
// generated by function: gen_binop_validator from: generate_tree.py
|
||||
|
||||
case ExpressionType.Add:
|
||||
case ExpressionType.And:
|
||||
case ExpressionType.Divide:
|
||||
case ExpressionType.Equal:
|
||||
case ExpressionType.ExclusiveOr:
|
||||
case ExpressionType.GreaterThan:
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
case ExpressionType.LeftShift:
|
||||
case ExpressionType.LessThan:
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
case ExpressionType.Modulo:
|
||||
case ExpressionType.Multiply:
|
||||
case ExpressionType.NotEqual:
|
||||
case ExpressionType.Or:
|
||||
case ExpressionType.Power:
|
||||
case ExpressionType.RightShift:
|
||||
case ExpressionType.Subtract:
|
||||
case ExpressionType.AddAssign:
|
||||
case ExpressionType.AndAssign:
|
||||
case ExpressionType.DivideAssign:
|
||||
case ExpressionType.ExclusiveOrAssign:
|
||||
case ExpressionType.LeftShiftAssign:
|
||||
case ExpressionType.ModuloAssign:
|
||||
case ExpressionType.MultiplyAssign:
|
||||
case ExpressionType.OrAssign:
|
||||
case ExpressionType.PowerAssign:
|
||||
case ExpressionType.RightShiftAssign:
|
||||
case ExpressionType.SubtractAssign:
|
||||
|
||||
// *** END GENERATED CODE ***
|
||||
|
||||
#endregion
|
||||
|
||||
case ExpressionType.Extension:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,368 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
#if CLR2
|
||||
using Microsoft.Scripting.Ast;
|
||||
#else
|
||||
using System.Linq.Expressions;
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Dynamic.Utils;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Dynamic {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a set of binding restrictions on the <see cref="DynamicMetaObject"/>under which the dynamic binding is valid.
|
||||
/// </summary>
|
||||
#if !SILVERLIGHT
|
||||
[DebuggerTypeProxy(typeof(BindingRestrictionsProxy)), DebuggerDisplay("{DebugView}")]
|
||||
#endif
|
||||
public abstract class BindingRestrictions {
|
||||
/// <summary>
|
||||
/// Represents an empty set of binding restrictions. This field is read only.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
|
||||
public static readonly BindingRestrictions Empty = new CustomRestriction(Expression.Constant(true));
|
||||
|
||||
private const int TypeRestrictionHash = 0x10000000;
|
||||
private const int InstanceRestrictionHash = 0x20000000;
|
||||
private const int CustomRestrictionHash = 0x40000000;
|
||||
|
||||
private BindingRestrictions() {
|
||||
}
|
||||
|
||||
// Overridden by specialized subclasses
|
||||
internal abstract Expression GetExpression();
|
||||
|
||||
/// <summary>
|
||||
/// Merges the set of binding restrictions with the current binding restrictions.
|
||||
/// </summary>
|
||||
/// <param name="restrictions">The set of restrictions with which to merge the current binding restrictions.</param>
|
||||
/// <returns>The new set of binding restrictions.</returns>
|
||||
public BindingRestrictions Merge(BindingRestrictions restrictions) {
|
||||
ContractUtils.RequiresNotNull(restrictions, "restrictions");
|
||||
if (this == Empty) {
|
||||
return restrictions;
|
||||
}
|
||||
if (restrictions == Empty) {
|
||||
return this;
|
||||
}
|
||||
return new MergedRestriction(this, restrictions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the binding restriction that check the expression for runtime type identity.
|
||||
/// </summary>
|
||||
/// <param name="expression">The expression to test.</param>
|
||||
/// <param name="type">The exact type to test.</param>
|
||||
/// <returns>The new binding restrictions.</returns>
|
||||
public static BindingRestrictions GetTypeRestriction(Expression expression, Type type) {
|
||||
ContractUtils.RequiresNotNull(expression, "expression");
|
||||
ContractUtils.RequiresNotNull(type, "type");
|
||||
|
||||
return new TypeRestriction(expression, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method takes a DynamicMetaObject, and returns an instance restriction for testing null if the object
|
||||
/// holds a null value, otherwise returns a type restriction.
|
||||
/// </summary>
|
||||
internal static BindingRestrictions GetTypeRestriction(DynamicMetaObject obj) {
|
||||
if (obj.Value == null && obj.HasValue) {
|
||||
return BindingRestrictions.GetInstanceRestriction(obj.Expression, null);
|
||||
} else {
|
||||
return BindingRestrictions.GetTypeRestriction(obj.Expression, obj.LimitType);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the binding restriction that checks the expression for object instance identity.
|
||||
/// </summary>
|
||||
/// <param name="expression">The expression to test.</param>
|
||||
/// <param name="instance">The exact object instance to test.</param>
|
||||
/// <returns>The new binding restrictions.</returns>
|
||||
public static BindingRestrictions GetInstanceRestriction(Expression expression, object instance) {
|
||||
ContractUtils.RequiresNotNull(expression, "expression");
|
||||
|
||||
return new InstanceRestriction(expression, instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the binding restriction that checks the expression for arbitrary immutable properties.
|
||||
/// </summary>
|
||||
/// <param name="expression">The expression expression the restrictions.</param>
|
||||
/// <returns>The new binding restrictions.</returns>
|
||||
/// <remarks>
|
||||
/// By convention, the general restrictions created by this method must only test
|
||||
/// immutable object properties.
|
||||
/// </remarks>
|
||||
public static BindingRestrictions GetExpressionRestriction(Expression expression) {
|
||||
ContractUtils.RequiresNotNull(expression, "expression");
|
||||
ContractUtils.Requires(expression.Type == typeof(bool), "expression");
|
||||
return new CustomRestriction(expression);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combines binding restrictions from the list of <see cref="DynamicMetaObject"/> instances into one set of restrictions.
|
||||
/// </summary>
|
||||
/// <param name="contributingObjects">The list of <see cref="DynamicMetaObject"/> instances from which to combine restrictions.</param>
|
||||
/// <returns>The new set of binding restrictions.</returns>
|
||||
public static BindingRestrictions Combine(IList<DynamicMetaObject> contributingObjects) {
|
||||
BindingRestrictions res = BindingRestrictions.Empty;
|
||||
if (contributingObjects != null) {
|
||||
foreach (DynamicMetaObject mo in contributingObjects) {
|
||||
if (mo != null) {
|
||||
res = res.Merge(mo.Restrictions);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a balanced tree of AndAlso nodes.
|
||||
/// We do this so the compiler won't stack overflow if we have many
|
||||
/// restrictions.
|
||||
/// </summary>
|
||||
private sealed class TestBuilder {
|
||||
private readonly Set<BindingRestrictions> _unique = new Set<BindingRestrictions>();
|
||||
private readonly Stack<AndNode> _tests = new Stack<AndNode>();
|
||||
|
||||
private struct AndNode {
|
||||
internal int Depth;
|
||||
internal Expression Node;
|
||||
}
|
||||
|
||||
internal void Append(BindingRestrictions restrictions) {
|
||||
if (_unique.Contains(restrictions)) {
|
||||
return;
|
||||
}
|
||||
_unique.Add(restrictions);
|
||||
|
||||
Push(restrictions.GetExpression(), 0);
|
||||
}
|
||||
|
||||
internal Expression ToExpression() {
|
||||
Expression result = _tests.Pop().Node;
|
||||
while (_tests.Count > 0) {
|
||||
result = Expression.AndAlso(_tests.Pop().Node, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void Push(Expression node, int depth) {
|
||||
while (_tests.Count > 0 && _tests.Peek().Depth == depth) {
|
||||
node = Expression.AndAlso(_tests.Pop().Node, node);
|
||||
depth++;
|
||||
}
|
||||
_tests.Push(new AndNode { Node = node, Depth = depth });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the <see cref="Expression"/> representing the binding restrictions.
|
||||
/// </summary>
|
||||
/// <returns>The expression tree representing the restrictions.</returns>
|
||||
public Expression ToExpression() {
|
||||
// We could optimize this better, e.g. common subexpression elimination
|
||||
// But for now, it's good enough.
|
||||
|
||||
if (this == Empty) {
|
||||
return Expression.Constant(true);
|
||||
}
|
||||
|
||||
var testBuilder = new TestBuilder();
|
||||
|
||||
// Visit the tree, left to right.
|
||||
// Use an explicit stack so we don't stack overflow.
|
||||
//
|
||||
// Left-most node is on top of the stack, so we always expand the
|
||||
// left most node each iteration.
|
||||
var stack = new Stack<BindingRestrictions>();
|
||||
stack.Push(this);
|
||||
do {
|
||||
var top = stack.Pop();
|
||||
var m = top as MergedRestriction;
|
||||
if (m != null) {
|
||||
stack.Push(m.Right);
|
||||
stack.Push(m.Left);
|
||||
} else {
|
||||
testBuilder.Append(top);
|
||||
}
|
||||
} while (stack.Count > 0);
|
||||
|
||||
return testBuilder.ToExpression();
|
||||
}
|
||||
|
||||
private sealed class MergedRestriction : BindingRestrictions {
|
||||
internal readonly BindingRestrictions Left;
|
||||
internal readonly BindingRestrictions Right;
|
||||
|
||||
internal MergedRestriction(BindingRestrictions left, BindingRestrictions right) {
|
||||
Left = left;
|
||||
Right = right;
|
||||
}
|
||||
internal override Expression GetExpression() {
|
||||
throw ContractUtils.Unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class CustomRestriction : BindingRestrictions {
|
||||
private readonly Expression _expression;
|
||||
|
||||
internal CustomRestriction(Expression expression) {
|
||||
_expression = expression;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
var other = obj as CustomRestriction;
|
||||
return other != null && other._expression == _expression;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return CustomRestrictionHash ^ _expression.GetHashCode();
|
||||
}
|
||||
|
||||
internal override Expression GetExpression() {
|
||||
return _expression;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class TypeRestriction : BindingRestrictions {
|
||||
private readonly Expression _expression;
|
||||
private readonly Type _type;
|
||||
|
||||
internal TypeRestriction(Expression parameter, Type type) {
|
||||
_expression = parameter;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
var other = obj as TypeRestriction;
|
||||
return other != null && TypeUtils.AreEquivalent(other._type, _type) && other._expression == _expression;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return TypeRestrictionHash ^ _expression.GetHashCode() ^ _type.GetHashCode();
|
||||
}
|
||||
|
||||
internal override Expression GetExpression() {
|
||||
return Expression.TypeEqual(_expression, _type);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class InstanceRestriction : BindingRestrictions {
|
||||
private readonly Expression _expression;
|
||||
private readonly object _instance;
|
||||
|
||||
internal InstanceRestriction(Expression parameter, object instance) {
|
||||
_expression = parameter;
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
var other = obj as InstanceRestriction;
|
||||
return other != null && other._instance == _instance && other._expression == _expression;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return InstanceRestrictionHash ^ RuntimeHelpers.GetHashCode(_instance) ^ _expression.GetHashCode();
|
||||
}
|
||||
|
||||
internal override Expression GetExpression() {
|
||||
if (_instance == null) {
|
||||
return Expression.Equal(
|
||||
Expression.Convert(_expression, typeof(object)),
|
||||
Expression.Constant(null)
|
||||
);
|
||||
}
|
||||
|
||||
ParameterExpression temp = Expression.Parameter(typeof(object), null);
|
||||
return Expression.Block(
|
||||
new[] { temp },
|
||||
Expression.Assign(
|
||||
temp,
|
||||
Expression.Property(
|
||||
Expression.Constant(new WeakReference(_instance)),
|
||||
typeof(WeakReference).GetProperty("Target")
|
||||
)
|
||||
),
|
||||
Expression.AndAlso(
|
||||
//check that WeekReference was not collected.
|
||||
Expression.NotEqual(temp, Expression.Constant(null)),
|
||||
Expression.Equal(
|
||||
Expression.Convert(_expression, typeof(object)),
|
||||
temp
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private string DebugView {
|
||||
get { return ToExpression().ToString(); }
|
||||
}
|
||||
|
||||
private sealed class BindingRestrictionsProxy {
|
||||
private readonly BindingRestrictions _node;
|
||||
|
||||
public BindingRestrictionsProxy(BindingRestrictions node) {
|
||||
_node = node;
|
||||
}
|
||||
|
||||
public bool IsEmpty {
|
||||
get { return _node == Empty; }
|
||||
}
|
||||
|
||||
public Expression Test {
|
||||
get { return _node.ToExpression(); }
|
||||
}
|
||||
|
||||
public BindingRestrictions[] Restrictions {
|
||||
get {
|
||||
var restrictions = new List<BindingRestrictions>();
|
||||
|
||||
// Visit the tree, left to right
|
||||
//
|
||||
// Left-most node is on top of the stack, so we always expand the
|
||||
// left most node each iteration.
|
||||
var stack = new Stack<BindingRestrictions>();
|
||||
stack.Push(_node);
|
||||
do {
|
||||
var top = stack.Pop();
|
||||
var m = top as MergedRestriction;
|
||||
if (m != null) {
|
||||
stack.Push(m.Right);
|
||||
stack.Push(m.Left);
|
||||
} else {
|
||||
restrictions.Add(top);
|
||||
}
|
||||
} while (stack.Count > 0);
|
||||
|
||||
return restrictions.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
// To prevent fxcop warning about this field
|
||||
return _node.DebugView;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
#if CLR2
|
||||
using Microsoft.Scripting.Ast;
|
||||
#else
|
||||
using System.Linq.Expressions;
|
||||
#endif
|
||||
#if SILVERLIGHT
|
||||
using System.Core;
|
||||
#endif
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Dynamic.Utils;
|
||||
|
||||
namespace System.Dynamic {
|
||||
|
||||
/// <summary>
|
||||
/// Describes arguments in the dynamic binding process.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ArgumentCount - all inclusive number of arguments.
|
||||
/// ArgumentNames - names for those arguments that are named.
|
||||
///
|
||||
/// Argument names match to the argument values in left to right order
|
||||
/// and last name corresponds to the last argument.
|
||||
///
|
||||
/// Example:
|
||||
/// Foo(arg1, arg2, arg3, name1 = arg4, name2 = arg5, name3 = arg6)
|
||||
///
|
||||
/// will correspond to:
|
||||
/// ArgumentCount: 6
|
||||
/// ArgumentNames: {"name1", "name2", "name3"}
|
||||
/// </remarks>
|
||||
public sealed class CallInfo {
|
||||
private readonly int _argCount;
|
||||
private readonly ReadOnlyCollection<string> _argNames;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new PositionalArgumentInfo.
|
||||
/// </summary>
|
||||
/// <param name="argCount">The number of arguments.</param>
|
||||
/// <param name="argNames">The argument names.</param>
|
||||
/// <returns>The new CallInfo</returns>
|
||||
public CallInfo(int argCount, params string[] argNames)
|
||||
: this(argCount, (IEnumerable<string>)argNames) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new CallInfo that represents arguments in the dynamic binding process.
|
||||
/// </summary>
|
||||
/// <param name="argCount">The number of arguments.</param>
|
||||
/// <param name="argNames">The argument names.</param>
|
||||
/// <returns>The new CallInfo</returns>
|
||||
public CallInfo(int argCount, IEnumerable<string> argNames) {
|
||||
ContractUtils.RequiresNotNull(argNames, "argNames");
|
||||
|
||||
var argNameCol = argNames.ToReadOnly();
|
||||
|
||||
if (argCount < argNameCol.Count) throw Error.ArgCntMustBeGreaterThanNameCnt();
|
||||
ContractUtils.RequiresNotNullItems(argNameCol, "argNames");
|
||||
|
||||
_argCount = argCount;
|
||||
_argNames = argNameCol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The number of arguments.
|
||||
/// </summary>
|
||||
public int ArgumentCount {
|
||||
get { return _argCount; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The argument names.
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<string> ArgumentNames {
|
||||
get { return _argNames; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for the current CallInfo.
|
||||
/// </summary>
|
||||
/// <returns>A hash code for the current CallInfo.</returns>
|
||||
public override int GetHashCode() {
|
||||
return _argCount ^ _argNames.ListHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified CallInfo instance is considered equal to the current.
|
||||
/// </summary>
|
||||
/// <param name="obj">The instance of CallInfo to compare with the current instance.</param>
|
||||
/// <returns>true if the specified instance is equal to the current one otherwise, false.</returns>
|
||||
public override bool Equals(object obj) {
|
||||
var other = obj as CallInfo;
|
||||
return _argCount == other._argCount && _argNames.ListEquals(other._argNames);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,235 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
#if CLR2
|
||||
using Microsoft.Scripting.Ast;
|
||||
#else
|
||||
using System.Linq.Expressions;
|
||||
#endif
|
||||
#if SILVERLIGHT
|
||||
using System.Core;
|
||||
#endif
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Dynamic;
|
||||
using System.Dynamic.Utils;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
|
||||
namespace System.Runtime.CompilerServices {
|
||||
/// <summary>
|
||||
/// Class responsible for runtime binding of the dynamic operations on the dynamic call site.
|
||||
/// </summary>
|
||||
public abstract class CallSiteBinder {
|
||||
private static readonly LabelTarget _updateLabel = Expression.Label("CallSiteBinder.UpdateLabel");
|
||||
|
||||
/// <summary>
|
||||
/// The Level 2 cache - all rules produced for the same binder.
|
||||
/// </summary>
|
||||
internal Dictionary<Type, object> Cache;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CallSiteBinder"/> class.
|
||||
/// </summary>
|
||||
protected CallSiteBinder() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a label that can be used to cause the binding to be updated. It
|
||||
/// indicates that the expression's binding is no longer valid.
|
||||
/// This is typically used when the "version" of a dynamic object has
|
||||
/// changed.
|
||||
/// </summary>
|
||||
public static LabelTarget UpdateLabel {
|
||||
get { return _updateLabel; }
|
||||
}
|
||||
|
||||
private sealed class LambdaSignature<T> where T : class {
|
||||
internal static readonly LambdaSignature<T> Instance = new LambdaSignature<T>();
|
||||
|
||||
internal readonly ReadOnlyCollection<ParameterExpression> Parameters;
|
||||
internal readonly LabelTarget ReturnLabel;
|
||||
|
||||
private LambdaSignature() {
|
||||
Type target = typeof(T);
|
||||
if (!target.IsSubclassOf(typeof(MulticastDelegate))) {
|
||||
throw Error.TypeParameterIsNotDelegate(target);
|
||||
}
|
||||
|
||||
MethodInfo invoke = target.GetMethod("Invoke");
|
||||
ParameterInfo[] pis = invoke.GetParametersCached();
|
||||
if (pis[0].ParameterType != typeof(CallSite)) {
|
||||
throw Error.FirstArgumentMustBeCallSite();
|
||||
}
|
||||
|
||||
var @params = new ParameterExpression[pis.Length - 1];
|
||||
for (int i = 0; i < @params.Length; i++) {
|
||||
@params[i] = Expression.Parameter(pis[i + 1].ParameterType, "$arg" + i);
|
||||
}
|
||||
|
||||
Parameters = new TrueReadOnlyCollection<ParameterExpression>(@params);
|
||||
ReturnLabel = Expression.Label(invoke.GetReturnType());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the runtime binding of the dynamic operation on a set of arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">An array of arguments to the dynamic operation.</param>
|
||||
/// <param name="parameters">The array of <see cref="ParameterExpression"/> instances that represent the parameters of the call site in the binding process.</param>
|
||||
/// <param name="returnLabel">A LabelTarget used to return the result of the dynamic binding.</param>
|
||||
/// <returns>
|
||||
/// An Expression that performs tests on the dynamic operation arguments, and
|
||||
/// performs the dynamic operation if hte tests are valid. If the tests fail on
|
||||
/// subsequent occurrences of the dynamic operation, Bind will be called again
|
||||
/// to produce a new <see cref="Expression"/> for the new argument types.
|
||||
/// </returns>
|
||||
public abstract Expression Bind(object[] args, ReadOnlyCollection<ParameterExpression> parameters, LabelTarget returnLabel);
|
||||
|
||||
/// <summary>
|
||||
/// Provides low-level runtime binding support. Classes can override this and provide a direct
|
||||
/// delegate for the implementation of rule. This can enable saving rules to disk, having
|
||||
/// specialized rules available at runtime, or providing a different caching policy.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The target type of the CallSite.</typeparam>
|
||||
/// <param name="site">The CallSite the bind is being performed for.</param>
|
||||
/// <param name="args">The arguments for the binder.</param>
|
||||
/// <returns>A new delegate which replaces the CallSite Target.</returns>
|
||||
public virtual T BindDelegate<T>(CallSite<T> site, object[] args) where T : class {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
internal T BindCore<T>(CallSite<T> site, object[] args) where T : class {
|
||||
//
|
||||
// Try to find a precompiled delegate, and return it if found.
|
||||
//
|
||||
T result = BindDelegate(site, args);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the Expression for the binding
|
||||
//
|
||||
var signature = LambdaSignature<T>.Instance;
|
||||
Expression binding = Bind(args, signature.Parameters, signature.ReturnLabel);
|
||||
|
||||
//
|
||||
// Check the produced rule
|
||||
//
|
||||
if (binding == null) {
|
||||
throw Error.NoOrInvalidRuleProduced();
|
||||
}
|
||||
|
||||
//
|
||||
// finally produce the new rule if we need to
|
||||
//
|
||||
#if !CLR2 && !SILVERLIGHT
|
||||
// We cannot compile rules in the heterogeneous app domains since they
|
||||
// may come from less trusted sources
|
||||
// Silverlight always uses a homogenous appdomain, so we don’t need this check
|
||||
if (!AppDomain.CurrentDomain.IsHomogenous) {
|
||||
throw Error.HomogenousAppDomainRequired();
|
||||
}
|
||||
#endif
|
||||
Expression<T> e = Stitch(binding, signature);
|
||||
T newRule = e.Compile();
|
||||
|
||||
CacheTarget(newRule);
|
||||
|
||||
return newRule;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a target to the cache of known targets. The cached targets will
|
||||
/// be scanned before calling BindDelegate to produce the new rule.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of target being added.</typeparam>
|
||||
/// <param name="target">The target delegate to be added to the cache.</param>
|
||||
protected void CacheTarget<T>(T target) where T : class {
|
||||
GetRuleCache<T>().AddRule(target);
|
||||
}
|
||||
|
||||
private static Expression<T> Stitch<T>(Expression binding, LambdaSignature<T> signature) where T : class {
|
||||
Type siteType = typeof(CallSite<T>);
|
||||
|
||||
var body = new ReadOnlyCollectionBuilder<Expression>(3);
|
||||
body.Add(binding);
|
||||
|
||||
var site = Expression.Parameter(typeof(CallSite), "$site");
|
||||
var @params = signature.Parameters.AddFirst(site);
|
||||
|
||||
Expression updLabel = Expression.Label(CallSiteBinder.UpdateLabel);
|
||||
|
||||
#if DEBUG
|
||||
// put the AST into the constant pool for debugging purposes
|
||||
updLabel = Expression.Block(
|
||||
Expression.Constant(binding, typeof(Expression)),
|
||||
updLabel
|
||||
);
|
||||
#endif
|
||||
|
||||
body.Add(updLabel);
|
||||
body.Add(
|
||||
Expression.Label(
|
||||
signature.ReturnLabel,
|
||||
Expression.Condition(
|
||||
Expression.Call(
|
||||
typeof(CallSiteOps).GetMethod("SetNotMatched"),
|
||||
@params.First()
|
||||
),
|
||||
Expression.Default(signature.ReturnLabel.Type),
|
||||
Expression.Invoke(
|
||||
Expression.Property(
|
||||
Expression.Convert(site, siteType),
|
||||
typeof(CallSite<T>).GetProperty("Update")
|
||||
),
|
||||
new TrueReadOnlyCollection<Expression>(@params)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
return new Expression<T>(
|
||||
Expression.Block(body),
|
||||
"CallSite.Target",
|
||||
true, // always compile the rules with tail call optimization
|
||||
new TrueReadOnlyCollection<ParameterExpression>(@params)
|
||||
);
|
||||
}
|
||||
|
||||
internal RuleCache<T> GetRuleCache<T>() where T : class {
|
||||
// make sure we have cache.
|
||||
if (Cache == null) {
|
||||
Interlocked.CompareExchange(ref Cache, new Dictionary<Type, object>(), null);
|
||||
}
|
||||
|
||||
object ruleCache;
|
||||
var cache = Cache;
|
||||
lock (cache) {
|
||||
if (!cache.TryGetValue(typeof(T), out ruleCache)) {
|
||||
cache[typeof(T)] = ruleCache = new RuleCache<T>();
|
||||
}
|
||||
}
|
||||
|
||||
RuleCache<T> result = ruleCache as RuleCache<T>;
|
||||
Debug.Assert(result != null);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
using System.Reflection;
|
||||
namespace System.Runtime.CompilerServices {
|
||||
/// <summary>
|
||||
/// Class that contains helper methods for DLR CallSites.
|
||||
/// </summary>
|
||||
public static class CallSiteHelpers {
|
||||
private static Type _knownNonDynamicMethodType = typeof(object).GetMethod("ToString").GetType();
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a <see cref="MethodBase"/> is internally used by DLR and should not
|
||||
/// be displayed on the language code's stack.
|
||||
/// </summary>
|
||||
/// <param name="mb">The input <see cref="MethodBase"/></param>
|
||||
/// <returns>
|
||||
/// True if the input <see cref="MethodBase"/> is internally used by DLR and should not
|
||||
/// be displayed on the language code's stack. Otherwise, false.
|
||||
/// </returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||||
public static bool IsInternalFrame(MethodBase mb) {
|
||||
//All the dynamic methods created for DLR rules have a special name.
|
||||
//We also check if the method has a different type than the known
|
||||
//non-static method. If it does, it is a dynamic method.
|
||||
//This could be improved if the CLR provides a way to attach some information
|
||||
//to the dynamic method we create, like CustomAttributes.
|
||||
if (mb.Name == "CallSite.Target" && mb.GetType() != _knownNonDynamicMethodType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Filter out the helper methods.
|
||||
if (mb.DeclaringType == typeof(System.Dynamic.UpdateDelegates)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Dynamic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace System.Runtime.CompilerServices {
|
||||
|
||||
// Conceptually these are instance methods on CallSite<T> but
|
||||
// we don't want users to see them
|
||||
|
||||
/// <summary>
|
||||
/// This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never), DebuggerStepThrough]
|
||||
public static class CallSiteOps {
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of a dynamic call site used for cache lookup.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the delegate of the <see cref="CallSite"/>.</typeparam>
|
||||
/// <returns>The new call site.</returns>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static CallSite<T> CreateMatchmaker<T>(CallSite<T> site) where T : class {
|
||||
var mm = site.CreateMatchMaker();
|
||||
CallSiteOps.ClearMatch(mm);
|
||||
return mm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a dynamic site requires an update.
|
||||
/// </summary>
|
||||
/// <param name="site">An instance of the dynamic call site.</param>
|
||||
/// <returns>true if rule does not need updating, false otherwise.</returns>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static bool SetNotMatched(CallSite site) {
|
||||
var res = site._match;
|
||||
site._match = false; //avoid branch here to make sure the method is inlined
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the executed rule matched
|
||||
/// </summary>
|
||||
/// <param name="site">An instance of the dynamic call site.</param>
|
||||
/// <returns>true if rule matched, false otherwise.</returns>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static bool GetMatch(CallSite site) {
|
||||
return site._match;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the match flag on the matchmaker call site.
|
||||
/// </summary>
|
||||
/// <param name="site">An instance of the dynamic call site.</param>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static void ClearMatch(CallSite site) {
|
||||
site._match = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a rule to the cache maintained on the dynamic call site.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the delegate of the <see cref="CallSite"/>.</typeparam>
|
||||
/// <param name="site">An instance of the dynamic call site.</param>
|
||||
/// <param name="rule">An instance of the call site rule.</param>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static void AddRule<T>(CallSite<T> site, T rule) where T : class {
|
||||
site.AddRule(rule);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates rules in the cache.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the delegate of the <see cref="CallSite"/>.</typeparam>
|
||||
/// <param name="this">An instance of the dynamic call site.</param>
|
||||
/// <param name="matched">The matched rule index.</param>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static void UpdateRules<T>(CallSite<T> @this, int matched) where T : class {
|
||||
if (matched > 1) {
|
||||
@this.MoveRule(matched);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dynamic binding rules from the call site.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the delegate of the <see cref="CallSite"/>.</typeparam>
|
||||
/// <param name="site">An instance of the dynamic call site.</param>
|
||||
/// <returns>An array of dynamic binding rules.</returns>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static T[] GetRules<T>(CallSite<T> site) where T : class {
|
||||
return site.Rules;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves binding rule cache.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the delegate of the <see cref="CallSite"/>.</typeparam>
|
||||
/// <param name="site">An instance of the dynamic call site.</param>
|
||||
/// <returns>The cache.</returns>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static RuleCache<T> GetRuleCache<T>(CallSite<T> site) where T : class {
|
||||
return site.Binder.GetRuleCache<T>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Moves the binding rule within the cache.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the delegate of the <see cref="CallSite"/>.</typeparam>
|
||||
/// <param name="cache">The call site rule cache.</param>
|
||||
/// <param name="rule">An instance of the call site rule.</param>
|
||||
/// <param name="i">An index of the call site rule.</param>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static void MoveRule<T>(RuleCache<T> cache, T rule, int i) where T : class {
|
||||
if (i > 1) {
|
||||
cache.MoveRule(rule, i);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the dynamic rule cache for rules applicable to the dynamic operation.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the delegate of the <see cref="CallSite"/>.</typeparam>
|
||||
/// <param name="cache">The cache.</param>
|
||||
/// <returns>The collection of applicable rules.</returns>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static T[] GetCachedRules<T>(RuleCache<T> cache) where T : class {
|
||||
return cache.GetRules();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the call site target with a new rule based on the arguments.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the delegate of the <see cref="CallSite"/>.</typeparam>
|
||||
/// <param name="binder">The call site binder.</param>
|
||||
/// <param name="site">An instance of the dynamic call site.</param>
|
||||
/// <param name="args">Arguments to the call site.</param>
|
||||
/// <returns>The new call site target.</returns>
|
||||
[Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static T Bind<T>(CallSiteBinder binder, CallSite<T> site, object[] args) where T : class {
|
||||
return binder.BindCore(site, args);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
using System.Dynamic.Utils;
|
||||
|
||||
namespace System.Dynamic {
|
||||
/// <summary>
|
||||
/// Represents the convert dynamic operation at the call site, providing the binding semantic and the details about the operation.
|
||||
/// </summary>
|
||||
public abstract class ConvertBinder : DynamicMetaObjectBinder {
|
||||
private readonly Type _type;
|
||||
private readonly bool _explicit;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new intsance of the <see cref="ConvertBinder" />.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to convert to.</param>
|
||||
/// <param name="explicit">true if the conversion should consider explicit conversions; otherwise, false.</param>
|
||||
protected ConvertBinder(Type type, bool @explicit) {
|
||||
ContractUtils.RequiresNotNull(type, "type");
|
||||
|
||||
_type = type;
|
||||
_explicit = @explicit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type to convert to.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
|
||||
public Type Type {
|
||||
get {
|
||||
return _type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating if the conversion should consider explicit conversions.
|
||||
/// </summary>
|
||||
public bool Explicit {
|
||||
get {
|
||||
return _explicit;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic convert operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic convert operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public DynamicMetaObject FallbackConvert(DynamicMetaObject target) {
|
||||
return FallbackConvert(target, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in the derived class, performs the binding of the dynamic convert operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic convert operation.</param>
|
||||
/// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public abstract DynamicMetaObject FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion);
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic convert operation.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic convert operation.</param>
|
||||
/// <param name="args">An array of arguments of the dynamic convert operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public sealed override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(target, "target");
|
||||
ContractUtils.Requires(args == null || args.Length == 0, "args");
|
||||
|
||||
return target.BindConvert(this);
|
||||
}
|
||||
|
||||
// this is a standard DynamicMetaObjectBinder
|
||||
internal override sealed bool IsStandardBinder {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result type of the operation.
|
||||
/// </summary>
|
||||
public override sealed Type ReturnType {
|
||||
get { return _type; }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
using System.Dynamic.Utils;
|
||||
|
||||
namespace System.Dynamic {
|
||||
/// <summary>
|
||||
/// Represents the create dynamic operation at the call site, providing the binding semantic and the details about the operation.
|
||||
/// </summary>
|
||||
public abstract class CreateInstanceBinder : DynamicMetaObjectBinder {
|
||||
private readonly CallInfo _callInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new intsance of the <see cref="CreateInstanceBinder" />.
|
||||
/// </summary>
|
||||
/// <param name="callInfo">The signature of the arguments at the call site.</param>
|
||||
protected CreateInstanceBinder(CallInfo callInfo) {
|
||||
ContractUtils.RequiresNotNull(callInfo, "callInfo");
|
||||
_callInfo = callInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result type of the operation.
|
||||
/// </summary>
|
||||
public override sealed Type ReturnType {
|
||||
get { return typeof(object); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the signature of the arguments at the call site.
|
||||
/// </summary>
|
||||
public CallInfo CallInfo {
|
||||
get { return _callInfo; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic create operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic create operation.</param>
|
||||
/// <param name="args">The arguments of the dynamic create operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public DynamicMetaObject FallbackCreateInstance(DynamicMetaObject target, DynamicMetaObject[] args) {
|
||||
return FallbackCreateInstance(target, args, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in the derived class, performs the binding of the dynamic create operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic create operation.</param>
|
||||
/// <param name="args">The arguments of the dynamic create operation.</param>
|
||||
/// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public abstract DynamicMetaObject FallbackCreateInstance(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion);
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic create operation.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic create operation.</param>
|
||||
/// <param name="args">An array of arguments of the dynamic create operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public sealed override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(target, "target");
|
||||
ContractUtils.RequiresNotNullItems(args, "args");
|
||||
|
||||
return target.BindCreateInstance(this, args);
|
||||
}
|
||||
|
||||
// this is a standard DynamicMetaObjectBinder
|
||||
internal override sealed bool IsStandardBinder {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
using System.Dynamic.Utils;
|
||||
|
||||
namespace System.Dynamic {
|
||||
/// <summary>
|
||||
/// Represents the dynamic delete index operation at the call site, providing the binding semantic and the details about the operation.
|
||||
/// </summary>
|
||||
public abstract class DeleteIndexBinder : DynamicMetaObjectBinder {
|
||||
private readonly CallInfo _callInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DeleteIndexBinder" />.
|
||||
/// </summary>
|
||||
/// <param name="callInfo">The signature of the arguments at the call site.</param>
|
||||
protected DeleteIndexBinder(CallInfo callInfo) {
|
||||
ContractUtils.RequiresNotNull(callInfo, "callInfo");
|
||||
_callInfo = callInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result type of the operation.
|
||||
/// </summary>
|
||||
public override sealed Type ReturnType {
|
||||
get { return typeof(void); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the signature of the arguments at the call site.
|
||||
/// </summary>
|
||||
public CallInfo CallInfo {
|
||||
get { return _callInfo; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic delete index operation.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic delete index operation.</param>
|
||||
/// <param name="args">An array of arguments of the dynamic delete index operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public sealed override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(target, "target");
|
||||
ContractUtils.RequiresNotNullItems(args, "args");
|
||||
|
||||
return target.BindDeleteIndex(this, args);
|
||||
}
|
||||
|
||||
// this is a standard DynamicMetaObjectBinder
|
||||
internal override sealed bool IsStandardBinder {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic delete index operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic delete index operation.</param>
|
||||
/// <param name="indexes">The arguments of the dynamic delete index operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public DynamicMetaObject FallbackDeleteIndex(DynamicMetaObject target, DynamicMetaObject[] indexes) {
|
||||
return FallbackDeleteIndex(target, indexes, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in the derived class, performs the binding of the dynamic delete index operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic delete index operation.</param>
|
||||
/// <param name="indexes">The arguments of the dynamic delete index operation.</param>
|
||||
/// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public abstract DynamicMetaObject FallbackDeleteIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject errorSuggestion);
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
using System.Dynamic.Utils;
|
||||
|
||||
namespace System.Dynamic {
|
||||
|
||||
/// <summary>
|
||||
/// Represents the dynamic delete member operation at the call site, providing the binding semantic and the details about the operation.
|
||||
/// </summary>
|
||||
public abstract class DeleteMemberBinder : DynamicMetaObjectBinder {
|
||||
private readonly string _name;
|
||||
private readonly bool _ignoreCase;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DeleteIndexBinder" />.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the member to delete.</param>
|
||||
/// <param name="ignoreCase">true if the name should be matched ignoring case; false otherwise.</param>
|
||||
protected DeleteMemberBinder(string name, bool ignoreCase) {
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
|
||||
_name = name;
|
||||
_ignoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the member to delete.
|
||||
/// </summary>
|
||||
public string Name {
|
||||
get {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating if the string comparison should ignore the case of the member name.
|
||||
/// </summary>
|
||||
public bool IgnoreCase {
|
||||
get {
|
||||
return _ignoreCase;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result type of the operation.
|
||||
/// </summary>
|
||||
public override sealed Type ReturnType {
|
||||
get { return typeof(void); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic delete member operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic delete member operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public DynamicMetaObject FallbackDeleteMember(DynamicMetaObject target) {
|
||||
return FallbackDeleteMember(target, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in the derived class, performs the binding of the dynamic delete member operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic delete member operation.</param>
|
||||
/// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public abstract DynamicMetaObject FallbackDeleteMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion);
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic delete member operation.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic delete member operation.</param>
|
||||
/// <param name="args">An array of arguments of the dynamic delete member operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public sealed override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(target, "target");
|
||||
ContractUtils.Requires(args == null || args.Length == 0);
|
||||
|
||||
return target.BindDeleteMember(this);
|
||||
}
|
||||
|
||||
|
||||
// this is a standard DynamicMetaObjectBinder
|
||||
internal override sealed bool IsStandardBinder {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,334 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
#if CLR2
|
||||
using Microsoft.Scripting.Ast;
|
||||
#else
|
||||
using System.Linq.Expressions;
|
||||
#endif
|
||||
|
||||
#if SILVERLIGHT
|
||||
using System.Core;
|
||||
#else
|
||||
using System.Runtime.Remoting;
|
||||
#endif
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic.Utils;
|
||||
using System.Reflection;
|
||||
|
||||
namespace System.Dynamic {
|
||||
/// <summary>
|
||||
/// Represents the dynamic binding and a binding logic of an object participating in the dynamic binding.
|
||||
/// </summary>
|
||||
public class DynamicMetaObject {
|
||||
private readonly Expression _expression;
|
||||
private readonly BindingRestrictions _restrictions;
|
||||
private readonly object _value;
|
||||
private readonly bool _hasValue;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an empty array of type <see cref="DynamicMetaObject"/>. This field is read only.
|
||||
/// </summary>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
|
||||
public static readonly DynamicMetaObject[] EmptyMetaObjects = new DynamicMetaObject[0];
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DynamicMetaObject"/> class.
|
||||
/// </summary>
|
||||
/// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param>
|
||||
/// <param name="restrictions">The set of binding restrictions under which the binding is valid.</param>
|
||||
public DynamicMetaObject(Expression expression, BindingRestrictions restrictions) {
|
||||
ContractUtils.RequiresNotNull(expression, "expression");
|
||||
ContractUtils.RequiresNotNull(restrictions, "restrictions");
|
||||
|
||||
_expression = expression;
|
||||
_restrictions = restrictions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DynamicMetaObject"/> class.
|
||||
/// </summary>
|
||||
/// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param>
|
||||
/// <param name="restrictions">The set of binding restrictions under which the binding is valid.</param>
|
||||
/// <param name="value">The runtime value represented by the <see cref="DynamicMetaObject"/>.</param>
|
||||
public DynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value)
|
||||
: this(expression, restrictions) {
|
||||
_value = value;
|
||||
_hasValue = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The expression representing the <see cref="DynamicMetaObject"/> during the dynamic binding process.
|
||||
/// </summary>
|
||||
public Expression Expression {
|
||||
get {
|
||||
return _expression;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The set of binding restrictions under which the binding is valid.
|
||||
/// </summary>
|
||||
public BindingRestrictions Restrictions {
|
||||
get {
|
||||
return _restrictions;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The runtime value represented by this <see cref="DynamicMetaObject"/>.
|
||||
/// </summary>
|
||||
public object Value {
|
||||
get {
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the <see cref="DynamicMetaObject"/> has the runtime value.
|
||||
/// </summary>
|
||||
public bool HasValue {
|
||||
get {
|
||||
return _hasValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Type"/> of the runtime value or null if the <see cref="DynamicMetaObject"/> has no value associated with it.
|
||||
/// </summary>
|
||||
public Type RuntimeType {
|
||||
get {
|
||||
if (_hasValue) {
|
||||
Type ct = Expression.Type;
|
||||
// valuetype at compile tyme, type cannot change.
|
||||
if (ct.IsValueType) {
|
||||
return ct;
|
||||
}
|
||||
if (_value != null) {
|
||||
return _value.GetType();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the limit type of the <see cref="DynamicMetaObject"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Represents the most specific type known about the object represented by the <see cref="DynamicMetaObject"/>. <see cref="RuntimeType"/> if runtime value is available, a type of the <see cref="Expression"/> otherwise.</remarks>
|
||||
public Type LimitType {
|
||||
get {
|
||||
return RuntimeType ?? Expression.Type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic conversion operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="ConvertBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindConvert(ConvertBinder binder) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackConvert(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic get member operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="GetMemberBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindGetMember(GetMemberBinder binder) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackGetMember(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic set member operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="SetMemberBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set member operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackSetMember(this, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic delete member operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="DeleteMemberBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackDeleteMember(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic get index operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="GetIndexBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the get index operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackGetIndex(this, indexes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic set index operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="SetIndexBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the set index operation.</param>
|
||||
/// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set index operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackSetIndex(this, indexes, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic delete index operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="DeleteIndexBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the delete index operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackDeleteIndex(this, indexes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic invoke member operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="InvokeMemberBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackInvokeMember(this, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic invoke operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="InvokeBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackInvoke(this, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic create instance operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="CreateInstanceBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the create instance operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackCreateInstance(this, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic unary operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="UnaryOperationBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackUnaryOperation(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic binary operation.
|
||||
/// </summary>
|
||||
/// <param name="binder">An instance of the <see cref="BinaryOperationBinder"/> that represents the details of the dynamic operation.</param>
|
||||
/// <param name="arg">An instance of the <see cref="DynamicMetaObject"/> representing the right hand side of the binary operation.</param>
|
||||
/// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public virtual DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg) {
|
||||
ContractUtils.RequiresNotNull(binder, "binder");
|
||||
return binder.FallbackBinaryOperation(this, arg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the enumeration of all dynamic member names.
|
||||
/// </summary>
|
||||
/// <returns>The list of dynamic member names.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
|
||||
public virtual IEnumerable<string> GetDynamicMemberNames() {
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the list of expressions represented by the <see cref="DynamicMetaObject"/> instances.
|
||||
/// </summary>
|
||||
/// <param name="objects">An array of <see cref="DynamicMetaObject"/> instances to extract expressions from.</param>
|
||||
/// <returns>The array of expressions.</returns>
|
||||
internal static Expression[] GetExpressions(DynamicMetaObject[] objects) {
|
||||
ContractUtils.RequiresNotNull(objects, "objects");
|
||||
|
||||
Expression[] res = new Expression[objects.Length];
|
||||
for (int i = 0; i < objects.Length; i++) {
|
||||
DynamicMetaObject mo = objects[i];
|
||||
ContractUtils.RequiresNotNull(mo, "objects");
|
||||
Expression expr = mo.Expression;
|
||||
ContractUtils.RequiresNotNull(expr, "objects");
|
||||
res[i] = expr;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a meta-object for the specified object.
|
||||
/// </summary>
|
||||
/// <param name="value">The object to get a meta-object for.</param>
|
||||
/// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param>
|
||||
/// <returns>
|
||||
/// If the given object implements <see cref="IDynamicMetaObjectProvider"/> and is not a remote object from outside the current AppDomain,
|
||||
/// returns the object's specific meta-object returned by <see cref="IDynamicMetaObjectProvider.GetMetaObject"/>. Otherwise a plain new meta-object
|
||||
/// with no restrictions is created and returned.
|
||||
/// </returns>
|
||||
public static DynamicMetaObject Create(object value, Expression expression) {
|
||||
ContractUtils.RequiresNotNull(expression, "expression");
|
||||
|
||||
IDynamicMetaObjectProvider ido = value as IDynamicMetaObjectProvider;
|
||||
#if !SILVERLIGHT
|
||||
if (ido != null && !RemotingServices.IsObjectOutOfAppDomain(value)) {
|
||||
#else
|
||||
if (ido != null) {
|
||||
#endif
|
||||
var idoMetaObject = ido.GetMetaObject(expression);
|
||||
|
||||
if (idoMetaObject == null ||
|
||||
!idoMetaObject.HasValue ||
|
||||
idoMetaObject.Value == null ||
|
||||
(object)idoMetaObject.Expression != (object)expression) {
|
||||
throw Error.InvalidMetaObjectCreated(ido.GetType());
|
||||
}
|
||||
|
||||
return idoMetaObject;
|
||||
} else {
|
||||
return new DynamicMetaObject(expression, BindingRestrictions.Empty, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,291 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
#if CLR2
|
||||
using Microsoft.Scripting.Ast;
|
||||
using Microsoft.Scripting.Ast.Compiler;
|
||||
#else
|
||||
using System.Linq.Expressions;
|
||||
using System.Linq.Expressions.Compiler;
|
||||
#endif
|
||||
|
||||
#if SILVERLIGHT
|
||||
using System.Core;
|
||||
#else
|
||||
using System.Runtime.Remoting;
|
||||
#endif
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Dynamic.Utils;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Dynamic {
|
||||
/// <summary>
|
||||
/// The dynamic call site binder that participates in the <see cref="DynamicMetaObject"/> binding protocol.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The <see cref="CallSiteBinder"/> performs the binding of the dynamic operation using the runtime values
|
||||
/// as input. On the other hand, the <see cref="DynamicMetaObjectBinder"/> participates in the <see cref="DynamicMetaObject"/>
|
||||
/// binding protocol.
|
||||
/// </remarks>
|
||||
public abstract class DynamicMetaObjectBinder : CallSiteBinder {
|
||||
|
||||
#region Public APIs
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DynamicMetaObjectBinder"/> class.
|
||||
/// </summary>
|
||||
protected DynamicMetaObjectBinder() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result type of the operation.
|
||||
/// </summary>
|
||||
public virtual Type ReturnType {
|
||||
get { return typeof(object); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the runtime binding of the dynamic operation on a set of arguments.
|
||||
/// </summary>
|
||||
/// <param name="args">An array of arguments to the dynamic operation.</param>
|
||||
/// <param name="parameters">The array of <see cref="ParameterExpression"/> instances that represent the parameters of the call site in the binding process.</param>
|
||||
/// <param name="returnLabel">A LabelTarget used to return the result of the dynamic binding.</param>
|
||||
/// <returns>
|
||||
/// An Expression that performs tests on the dynamic operation arguments, and
|
||||
/// performs the dynamic operation if the tests are valid. If the tests fail on
|
||||
/// subsequent occurrences of the dynamic operation, Bind will be called again
|
||||
/// to produce a new <see cref="Expression"/> for the new argument types.
|
||||
/// </returns>
|
||||
public sealed override Expression Bind(object[] args, ReadOnlyCollection<ParameterExpression> parameters, LabelTarget returnLabel) {
|
||||
ContractUtils.RequiresNotNull(args, "args");
|
||||
ContractUtils.RequiresNotNull(parameters, "parameters");
|
||||
ContractUtils.RequiresNotNull(returnLabel, "returnLabel");
|
||||
if (args.Length == 0) {
|
||||
throw Error.OutOfRange("args.Length", 1);
|
||||
}
|
||||
if (parameters.Count == 0) {
|
||||
throw Error.OutOfRange("parameters.Count", 1);
|
||||
}
|
||||
if (args.Length != parameters.Count) {
|
||||
throw new ArgumentOutOfRangeException("args");
|
||||
}
|
||||
|
||||
// Ensure that the binder's ReturnType matches CallSite's return
|
||||
// type. We do this so meta objects and language binders can
|
||||
// compose trees together without needing to insert converts.
|
||||
Type expectedResult;
|
||||
if (IsStandardBinder) {
|
||||
expectedResult = ReturnType;
|
||||
|
||||
if (returnLabel.Type != typeof(void) &&
|
||||
!TypeUtils.AreReferenceAssignable(returnLabel.Type, expectedResult)) {
|
||||
throw Error.BinderNotCompatibleWithCallSite(expectedResult, this, returnLabel.Type);
|
||||
}
|
||||
} else {
|
||||
// Even for non-standard binders, we have to at least make sure
|
||||
// it works with the CallSite's type to build the return.
|
||||
expectedResult = returnLabel.Type;
|
||||
}
|
||||
|
||||
DynamicMetaObject target = DynamicMetaObject.Create(args[0], parameters[0]);
|
||||
DynamicMetaObject[] metaArgs = CreateArgumentMetaObjects(args, parameters);
|
||||
|
||||
DynamicMetaObject binding = Bind(target, metaArgs);
|
||||
|
||||
if (binding == null) {
|
||||
throw Error.BindingCannotBeNull();
|
||||
}
|
||||
|
||||
Expression body = binding.Expression;
|
||||
BindingRestrictions restrictions = binding.Restrictions;
|
||||
|
||||
// Ensure the result matches the expected result type.
|
||||
if (expectedResult != typeof(void) &&
|
||||
!TypeUtils.AreReferenceAssignable(expectedResult, body.Type)) {
|
||||
|
||||
//
|
||||
// Blame the last person that handled the result: assume it's
|
||||
// the dynamic object (if any), otherwise blame the language.
|
||||
//
|
||||
if (target.Value is IDynamicMetaObjectProvider) {
|
||||
throw Error.DynamicObjectResultNotAssignable(body.Type, target.Value.GetType(), this, expectedResult);
|
||||
} else {
|
||||
throw Error.DynamicBinderResultNotAssignable(body.Type, this, expectedResult);
|
||||
}
|
||||
}
|
||||
|
||||
// if the target is IDO, standard binders ask it to bind the rule so we may have a target-specific binding.
|
||||
// it makes sense to restrict on the target's type in such cases.
|
||||
// ideally IDO metaobjects should do this, but they often miss that type of "this" is significant.
|
||||
if (IsStandardBinder && args[0] as IDynamicMetaObjectProvider != null) {
|
||||
if (restrictions == BindingRestrictions.Empty) {
|
||||
throw Error.DynamicBindingNeedsRestrictions(target.Value.GetType(), this);
|
||||
}
|
||||
}
|
||||
|
||||
restrictions = AddRemoteObjectRestrictions(restrictions, args, parameters);
|
||||
|
||||
// Add the return
|
||||
if (body.NodeType != ExpressionType.Goto) {
|
||||
body = Expression.Return(returnLabel, body);
|
||||
}
|
||||
|
||||
// Finally, add restrictions
|
||||
if (restrictions != BindingRestrictions.Empty) {
|
||||
body = Expression.IfThen(restrictions.ToExpression(), body);
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
private static DynamicMetaObject[] CreateArgumentMetaObjects(object[] args, ReadOnlyCollection<ParameterExpression> parameters) {
|
||||
DynamicMetaObject[] mos;
|
||||
if (args.Length != 1) {
|
||||
mos = new DynamicMetaObject[args.Length - 1];
|
||||
for (int i = 1; i < args.Length; i++) {
|
||||
mos[i - 1] = DynamicMetaObject.Create(args[i], parameters[i]);
|
||||
}
|
||||
} else {
|
||||
mos = DynamicMetaObject.EmptyMetaObjects;
|
||||
}
|
||||
return mos;
|
||||
}
|
||||
|
||||
private static BindingRestrictions AddRemoteObjectRestrictions(BindingRestrictions restrictions, object[] args, ReadOnlyCollection<ParameterExpression> parameters) {
|
||||
#if !SILVERLIGHT
|
||||
|
||||
for (int i = 0; i < parameters.Count; i++) {
|
||||
var expr = parameters[i];
|
||||
var value = args[i] as MarshalByRefObject;
|
||||
|
||||
// special case for MBR objects.
|
||||
// when MBR objects are remoted they can have different conversion behavior
|
||||
// so bindings created for local and remote objects should not be mixed.
|
||||
if (value != null && !IsComObject(value)) {
|
||||
BindingRestrictions remotedRestriction;
|
||||
if (RemotingServices.IsObjectOutOfAppDomain(value)) {
|
||||
remotedRestriction = BindingRestrictions.GetExpressionRestriction(
|
||||
Expression.AndAlso(
|
||||
Expression.NotEqual(expr, Expression.Constant(null)),
|
||||
Expression.Call(
|
||||
typeof(RemotingServices).GetMethod("IsObjectOutOfAppDomain"),
|
||||
expr
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
remotedRestriction = BindingRestrictions.GetExpressionRestriction(
|
||||
Expression.AndAlso(
|
||||
Expression.NotEqual(expr, Expression.Constant(null)),
|
||||
Expression.Not(
|
||||
Expression.Call(
|
||||
typeof(RemotingServices).GetMethod("IsObjectOutOfAppDomain"),
|
||||
expr
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
restrictions = restrictions.Merge(remotedRestriction);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
return restrictions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in the derived class, performs the binding of the dynamic operation.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic operation.</param>
|
||||
/// <param name="args">An array of arguments of the dynamic operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public abstract DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an expression that will cause the binding to be updated. It
|
||||
/// indicates that the expression's binding is no longer valid.
|
||||
/// This is typically used when the "version" of a dynamic object has
|
||||
/// changed.
|
||||
/// </summary>
|
||||
/// <param name="type">The <see cref="Expression.Type">Type</see> property of the resulting expression; any type is allowed.</param>
|
||||
/// <returns>The update expression.</returns>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
|
||||
public Expression GetUpdateExpression(Type type) {
|
||||
return Expression.Goto(CallSiteBinder.UpdateLabel, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defers the binding of the operation until later time when the runtime values of all dynamic operation arguments have been computed.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic operation.</param>
|
||||
/// <param name="args">An array of arguments of the dynamic operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public DynamicMetaObject Defer(DynamicMetaObject target, params DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(target, "target");
|
||||
|
||||
if (args == null) {
|
||||
return MakeDeferred(target.Restrictions, target);
|
||||
} else {
|
||||
return MakeDeferred(
|
||||
target.Restrictions.Merge(BindingRestrictions.Combine(args)),
|
||||
args.AddFirst(target)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defers the binding of the operation until later time when the runtime values of all dynamic operation arguments have been computed.
|
||||
/// </summary>
|
||||
/// <param name="args">An array of arguments of the dynamic operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public DynamicMetaObject Defer(params DynamicMetaObject[] args) {
|
||||
return MakeDeferred(BindingRestrictions.Combine(args), args);
|
||||
}
|
||||
|
||||
private DynamicMetaObject MakeDeferred(BindingRestrictions rs, params DynamicMetaObject[] args) {
|
||||
var exprs = DynamicMetaObject.GetExpressions(args);
|
||||
|
||||
Type delegateType = DelegateHelpers.MakeDeferredSiteDelegate(args, ReturnType);
|
||||
|
||||
// Because we know the arguments match the delegate type (we just created the argument types)
|
||||
// we go directly to DynamicExpression.Make to avoid a bunch of unnecessary argument validation
|
||||
return new DynamicMetaObject(
|
||||
DynamicExpression.Make(ReturnType, delegateType, this, new TrueReadOnlyCollection<Expression>(exprs)),
|
||||
rs
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// used to detect standard MetaObjectBinders.
|
||||
internal virtual bool IsStandardBinder {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if !SILVERLIGHT
|
||||
private static readonly Type ComObjectType = typeof(object).Assembly.GetType("System.__ComObject");
|
||||
private static bool IsComObject(object obj) {
|
||||
// we can't use System.Runtime.InteropServices.Marshal.IsComObject(obj) since it doesn't work in partial trust
|
||||
return obj != null && ComObjectType.IsAssignableFrom(obj.GetType());
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,183 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Dynamic.Utils;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Dynamic {
|
||||
/// <summary>
|
||||
/// Represents a dynamically assigned class. Expando objects which share the same
|
||||
/// members will share the same class. Classes are dynamically assigned as the
|
||||
/// expando object gains members.
|
||||
/// </summary>
|
||||
internal class ExpandoClass {
|
||||
private readonly string[] _keys; // list of names associated with each element in the data array, sorted
|
||||
private readonly int _hashCode; // pre-calculated hash code of all the keys the class contains
|
||||
private Dictionary<int, List<WeakReference>> _transitions; // cached transitions
|
||||
|
||||
private const int EmptyHashCode = 6551; // hash code of the empty ExpandoClass.
|
||||
|
||||
internal static ExpandoClass Empty = new ExpandoClass(); // The empty Expando class - all Expando objects start off w/ this class.
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the empty ExpandoClass. This is the class used when an
|
||||
/// empty Expando object is initially constructed.
|
||||
/// </summary>
|
||||
internal ExpandoClass() {
|
||||
_hashCode = EmptyHashCode;
|
||||
_keys = new string[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new ExpandoClass that can hold onto the specified keys. The
|
||||
/// keys must be sorted ordinally. The hash code must be precalculated for
|
||||
/// the keys.
|
||||
/// </summary>
|
||||
internal ExpandoClass(string[] keys, int hashCode) {
|
||||
_hashCode = hashCode;
|
||||
_keys = keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds or creates a new ExpandoClass given the existing set of keys
|
||||
/// in this ExpandoClass plus the new key to be added. Members in an
|
||||
/// ExpandoClass are always stored case sensitively.
|
||||
/// </summary>
|
||||
internal ExpandoClass FindNewClass(string newKey) {
|
||||
// just XOR the newKey hash code
|
||||
int hashCode = _hashCode ^ newKey.GetHashCode();
|
||||
|
||||
lock (this) {
|
||||
List<WeakReference> infos = GetTransitionList(hashCode);
|
||||
|
||||
for (int i = 0; i < infos.Count; i++) {
|
||||
ExpandoClass klass = infos[i].Target as ExpandoClass;
|
||||
if (klass == null) {
|
||||
infos.RemoveAt(i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.Equals(klass._keys[klass._keys.Length - 1], newKey, StringComparison.Ordinal)) {
|
||||
// the new key is the key we added in this transition
|
||||
return klass;
|
||||
}
|
||||
}
|
||||
|
||||
// no applicable transition, create a new one
|
||||
string[] keys = new string[_keys.Length + 1];
|
||||
Array.Copy(_keys, keys, _keys.Length);
|
||||
keys[_keys.Length] = newKey;
|
||||
ExpandoClass ec = new ExpandoClass(keys, hashCode);
|
||||
|
||||
infos.Add(new WeakReference(ec));
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the lists of transitions that are valid from this ExpandoClass
|
||||
/// to an ExpandoClass whos keys hash to the apporopriate hash code.
|
||||
/// </summary>
|
||||
private List<WeakReference> GetTransitionList(int hashCode) {
|
||||
if (_transitions == null) {
|
||||
_transitions = new Dictionary<int, List<WeakReference>>();
|
||||
}
|
||||
|
||||
List<WeakReference> infos;
|
||||
if (!_transitions.TryGetValue(hashCode, out infos)) {
|
||||
_transitions[hashCode] = infos = new List<WeakReference>();
|
||||
}
|
||||
|
||||
return infos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index at which the value should be stored for the specified name.
|
||||
/// </summary>
|
||||
internal int GetValueIndex(string name, bool caseInsensitive, ExpandoObject obj) {
|
||||
if (caseInsensitive) {
|
||||
return GetValueIndexCaseInsensitive(name, obj);
|
||||
} else {
|
||||
return GetValueIndexCaseSensitive(name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index at which the value should be stored for the specified name
|
||||
/// case sensitively. Returns the index even if the member is marked as deleted.
|
||||
/// </summary>
|
||||
internal int GetValueIndexCaseSensitive(string name) {
|
||||
for (int i = 0; i < _keys.Length; i++) {
|
||||
if (string.Equals(
|
||||
_keys[i],
|
||||
name,
|
||||
StringComparison.Ordinal)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return ExpandoObject.NoMatch;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index at which the value should be stored for the specified name,
|
||||
/// the method is only used in the case-insensitive case.
|
||||
/// </summary>
|
||||
/// <param name="name">the name of the member</param>
|
||||
/// <param name="obj">The ExpandoObject associated with the class
|
||||
/// that is used to check if a member has been deleted.</param>
|
||||
/// <returns>
|
||||
/// the exact match if there is one
|
||||
/// if there is exactly one member with case insensitive match, return it
|
||||
/// otherwise we throw AmbiguousMatchException.
|
||||
/// </returns>
|
||||
private int GetValueIndexCaseInsensitive(string name, ExpandoObject obj) {
|
||||
int caseInsensitiveMatch = ExpandoObject.NoMatch; //the location of the case-insensitive matching member
|
||||
lock (obj.LockObject) {
|
||||
for (int i = _keys.Length - 1; i >= 0; i--) {
|
||||
if (string.Equals(
|
||||
_keys[i],
|
||||
name,
|
||||
StringComparison.OrdinalIgnoreCase)) {
|
||||
//if the matching member is deleted, continue searching
|
||||
if (!obj.IsDeletedMember(i)) {
|
||||
if (caseInsensitiveMatch == ExpandoObject.NoMatch) {
|
||||
caseInsensitiveMatch = i;
|
||||
} else {
|
||||
//Ambigous match, stop searching
|
||||
return ExpandoObject.AmbiguousMatchFound;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//There is exactly one member with case insensitive match.
|
||||
return caseInsensitiveMatch;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the names of the keys that can be stored in the Expando class. The
|
||||
/// list is sorted ordinally.
|
||||
/// </summary>
|
||||
internal string[] Keys {
|
||||
get {
|
||||
return _keys;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,88 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
using System.Dynamic.Utils;
|
||||
|
||||
namespace System.Dynamic {
|
||||
|
||||
/// <summary>
|
||||
/// Represents the dynamic get index operation at the call site, providing the binding semantic and the details about the operation.
|
||||
/// </summary>
|
||||
public abstract class GetIndexBinder : DynamicMetaObjectBinder {
|
||||
private readonly CallInfo _callInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GetIndexBinder" />.
|
||||
/// </summary>
|
||||
/// <param name="callInfo">The signature of the arguments at the call site.</param>
|
||||
protected GetIndexBinder(CallInfo callInfo) {
|
||||
ContractUtils.RequiresNotNull(callInfo, "callInfo");
|
||||
_callInfo = callInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result type of the operation.
|
||||
/// </summary>
|
||||
public override sealed Type ReturnType {
|
||||
get { return typeof(object); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the signature of the arguments at the call site.
|
||||
/// </summary>
|
||||
public CallInfo CallInfo {
|
||||
get { return _callInfo; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic get index operation.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic get index operation.</param>
|
||||
/// <param name="args">An array of arguments of the dynamic get index operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public sealed override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(target, "target");
|
||||
ContractUtils.RequiresNotNullItems(args, "args");
|
||||
|
||||
return target.BindGetIndex(this, args);
|
||||
}
|
||||
|
||||
// this is a standard DynamicMetaObjectBinder
|
||||
internal override sealed bool IsStandardBinder {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic get index operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic get index operation.</param>
|
||||
/// <param name="indexes">The arguments of the dynamic get index operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public DynamicMetaObject FallbackGetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes) {
|
||||
return FallbackGetIndex(target, indexes, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in the derived class, performs the binding of the dynamic get index operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic get index operation.</param>
|
||||
/// <param name="indexes">The arguments of the dynamic get index operation.</param>
|
||||
/// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public abstract DynamicMetaObject FallbackGetIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject errorSuggestion);
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
using System.Dynamic.Utils;
|
||||
|
||||
namespace System.Dynamic {
|
||||
/// <summary>
|
||||
/// Represents the dynamic get member operation at the call site, providing the binding semantic and the details about the operation.
|
||||
/// </summary>
|
||||
public abstract class GetMemberBinder : DynamicMetaObjectBinder {
|
||||
private readonly string _name;
|
||||
private readonly bool _ignoreCase;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GetMemberBinder" />.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the member to get.</param>
|
||||
/// <param name="ignoreCase">true if the name should be matched ignoring case; false otherwise.</param>
|
||||
protected GetMemberBinder(string name, bool ignoreCase) {
|
||||
ContractUtils.RequiresNotNull(name, "name");
|
||||
|
||||
_name = name;
|
||||
_ignoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The result type of the operation.
|
||||
/// </summary>
|
||||
public override sealed Type ReturnType {
|
||||
get { return typeof(object); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the member to get.
|
||||
/// </summary>
|
||||
public string Name {
|
||||
get {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating if the string comparison should ignore the case of the member name.
|
||||
/// </summary>
|
||||
public bool IgnoreCase {
|
||||
get {
|
||||
return _ignoreCase;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic get member operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic get member operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public DynamicMetaObject FallbackGetMember(DynamicMetaObject target) {
|
||||
return FallbackGetMember(target, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in the derived class, performs the binding of the dynamic get member operation if the target dynamic object cannot bind.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic get member operation.</param>
|
||||
/// <param name="errorSuggestion">The binding result to use if binding fails, or null.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public abstract DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion);
|
||||
|
||||
/// <summary>
|
||||
/// Performs the binding of the dynamic get member operation.
|
||||
/// </summary>
|
||||
/// <param name="target">The target of the dynamic get member operation.</param>
|
||||
/// <param name="args">An array of arguments of the dynamic get member operation.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
|
||||
public sealed override DynamicMetaObject Bind(DynamicMetaObject target, params DynamicMetaObject[] args) {
|
||||
ContractUtils.RequiresNotNull(target, "target");
|
||||
ContractUtils.Requires(args == null || args.Length == 0, "args");
|
||||
|
||||
return target.BindGetMember(this);
|
||||
}
|
||||
|
||||
// this is a standard DynamicMetaObjectBinder
|
||||
internal override sealed bool IsStandardBinder {
|
||||
get {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
#if CLR2
|
||||
using Microsoft.Scripting.Ast;
|
||||
#else
|
||||
using System.Linq.Expressions;
|
||||
#endif
|
||||
|
||||
namespace System.Dynamic {
|
||||
/// <summary>
|
||||
/// Represents a dynamic object, that can have its operations bound at runtime.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Objects that want to participate in the binding process should implement an IDynamicMetaObjectProvider interface,
|
||||
/// and implement <see cref="IDynamicMetaObjectProvider.GetMetaObject" /> to return a <see cref="DynamicMetaObject" />.
|
||||
/// </remarks>
|
||||
public interface IDynamicMetaObjectProvider {
|
||||
/// <summary>
|
||||
/// Returns the <see cref="DynamicMetaObject" /> responsible for binding operations performed on this object.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The expression tree representation of the runtime value.</param>
|
||||
/// <returns>The <see cref="DynamicMetaObject" /> to bind this object.</returns>
|
||||
DynamicMetaObject GetMetaObject(Expression parameter);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/* ****************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* This source code is subject to terms and conditions of the Apache License, Version 2.0. A
|
||||
* copy of the license can be found in the License.html file at the root of this distribution. If
|
||||
* you cannot locate the Apache License, Version 2.0, please send an email to
|
||||
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
|
||||
* by the terms of the Apache License, Version 2.0.
|
||||
*
|
||||
* You must not remove this notice, or any other, from this software.
|
||||
*
|
||||
*
|
||||
* ***************************************************************************/
|
||||
|
||||
namespace System.Dynamic {
|
||||
/// <summary>
|
||||
/// Represents information about a dynamic get member operation, indicating
|
||||
/// if the get member should invoke properties when performing the get.
|
||||
/// </summary>
|
||||
public interface IInvokeOnGetBinder {
|
||||
/// <summary>
|
||||
/// Gets the value indicating if this GetMember should invoke properties
|
||||
/// when performing the get. The default value when this interface is not present
|
||||
/// is true.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property is used by some languages to get a better COM interop experience.
|
||||
/// When the value is set to false, the dynamic COM object won't invoke the object
|
||||
/// but will instead bind to the name, and return an object that can be invoked or
|
||||
/// indexed later. This is useful for indexed properties and languages that don't
|
||||
/// produce InvokeMember call sites.
|
||||
/// </remarks>
|
||||
bool InvokeOnGet { get; }
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user