/* ****************************************************************************
*
* 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 !FEATURE_CORE_DLR
using Microsoft.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
#if FEATURE_REMOTING
using System.Runtime.Remoting;
#endif
using System.Collections.Generic;
using System.Dynamic.Utils;
using System.Reflection;
namespace System.Dynamic {
///
/// Represents the dynamic binding and a binding logic of an object participating in the dynamic binding.
///
public class DynamicMetaObject {
private readonly Expression _expression;
private readonly BindingRestrictions _restrictions;
private readonly object _value;
private readonly bool _hasValue;
///
/// Represents an empty array of type . This field is read only.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
public static readonly DynamicMetaObject[] EmptyMetaObjects = new DynamicMetaObject[0];
///
/// Initializes a new instance of the class.
///
/// The expression representing this during the dynamic binding process.
/// The set of binding restrictions under which the binding is valid.
public DynamicMetaObject(Expression expression, BindingRestrictions restrictions) {
ContractUtils.RequiresNotNull(expression, "expression");
ContractUtils.RequiresNotNull(restrictions, "restrictions");
_expression = expression;
_restrictions = restrictions;
}
///
/// Initializes a new instance of the class.
///
/// The expression representing this during the dynamic binding process.
/// The set of binding restrictions under which the binding is valid.
/// The runtime value represented by the .
public DynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value)
: this(expression, restrictions) {
_value = value;
_hasValue = true;
}
///
/// The expression representing the during the dynamic binding process.
///
public Expression Expression {
get {
return _expression;
}
}
///
/// The set of binding restrictions under which the binding is valid.
///
public BindingRestrictions Restrictions {
get {
return _restrictions;
}
}
///
/// The runtime value represented by this .
///
public object Value {
get {
return _value;
}
}
///
/// Gets a value indicating whether the has the runtime value.
///
public bool HasValue {
get {
return _hasValue;
}
}
///
/// Gets the of the runtime value or null if the has no value associated with it.
///
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;
}
}
}
///
/// Gets the limit type of the .
///
/// Represents the most specific type known about the object represented by the . if runtime value is available, a type of the otherwise.
public Type LimitType {
get {
return RuntimeType ?? Expression.Type;
}
}
///
/// Performs the binding of the dynamic conversion operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindConvert(ConvertBinder binder) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackConvert(this);
}
///
/// Performs the binding of the dynamic get member operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindGetMember(GetMemberBinder binder) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackGetMember(this);
}
///
/// Performs the binding of the dynamic set member operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// The representing the value for the set member operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackSetMember(this, value);
}
///
/// Performs the binding of the dynamic delete member operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackDeleteMember(this);
}
///
/// Performs the binding of the dynamic get index operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// An array of instances - indexes for the get index operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackGetIndex(this, indexes);
}
///
/// Performs the binding of the dynamic set index operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// An array of instances - indexes for the set index operation.
/// The representing the value for the set index operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackSetIndex(this, indexes, value);
}
///
/// Performs the binding of the dynamic delete index operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// An array of instances - indexes for the delete index operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackDeleteIndex(this, indexes);
}
///
/// Performs the binding of the dynamic invoke member operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// An array of instances - arguments to the invoke member operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackInvokeMember(this, args);
}
///
/// Performs the binding of the dynamic invoke operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// An array of instances - arguments to the invoke operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackInvoke(this, args);
}
///
/// Performs the binding of the dynamic create instance operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// An array of instances - arguments to the create instance operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackCreateInstance(this, args);
}
///
/// Performs the binding of the dynamic unary operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackUnaryOperation(this);
}
///
/// Performs the binding of the dynamic binary operation.
///
/// An instance of the that represents the details of the dynamic operation.
/// An instance of the representing the right hand side of the binary operation.
/// The new representing the result of the binding.
public virtual DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg) {
ContractUtils.RequiresNotNull(binder, "binder");
return binder.FallbackBinaryOperation(this, arg);
}
///
/// Returns the enumeration of all dynamic member names.
///
/// The list of dynamic member names.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
public virtual IEnumerable GetDynamicMemberNames() {
return new string[0];
}
///
/// Returns the list of expressions represented by the instances.
///
/// An array of instances to extract expressions from.
/// The array of expressions.
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;
}
///
/// Creates a meta-object for the specified object.
///
/// The object to get a meta-object for.
/// The expression representing this during the dynamic binding process.
///
/// If the given object implements and is not a remote object from outside the current AppDomain,
/// returns the object's specific meta-object returned by . Otherwise a plain new meta-object
/// with no restrictions is created and returned.
///
public static DynamicMetaObject Create(object value, Expression expression) {
ContractUtils.RequiresNotNull(expression, "expression");
IDynamicMetaObjectProvider ido = value as IDynamicMetaObjectProvider;
#if FEATURE_REMOTING
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);
}
}
}
}