Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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

View File

@ -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 dont 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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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; }
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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
}
}

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}

View File

@ -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