PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting.Core/Actions/DynamicMetaObject.cs

https://bitbucket.org/stefanrusek/xronos
C# | 382 lines | 188 code | 39 blank | 155 comment | 21 complexity | ac866f8d19962fdbe1d25b382ef9f984 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System; using Microsoft;
  16. using System.Collections.Generic;
  17. #if CODEPLEX_40
  18. using System.Dynamic.Utils;
  19. using System.Linq.Expressions;
  20. #else
  21. using Microsoft.Scripting.Utils;
  22. using Microsoft.Linq.Expressions;
  23. #endif
  24. using System.Reflection;
  25. using System.Runtime.Remoting;
  26. #if CODEPLEX_40
  27. namespace System.Dynamic {
  28. #else
  29. namespace Microsoft.Scripting {
  30. #endif
  31. /// <summary>
  32. /// Represents the dynamic binding and a binding logic of an object participating in the dynamic binding.
  33. /// </summary>
  34. public class DynamicMetaObject {
  35. private readonly Expression _expression;
  36. private readonly BindingRestrictions _restrictions;
  37. private readonly object _value;
  38. private readonly bool _hasValue;
  39. /// <summary>
  40. /// Represents an empty array of type <see cref="DynamicMetaObject"/>. This field is read only.
  41. /// </summary>
  42. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")]
  43. public static readonly DynamicMetaObject[] EmptyMetaObjects = new DynamicMetaObject[0];
  44. /// <summary>
  45. /// Initializes a new instance of the <see cref="DynamicMetaObject"/> class.
  46. /// </summary>
  47. /// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param>
  48. /// <param name="restrictions">The set of binding restrictions under which the binding is valid.</param>
  49. public DynamicMetaObject(Expression expression, BindingRestrictions restrictions) {
  50. ContractUtils.RequiresNotNull(expression, "expression");
  51. ContractUtils.RequiresNotNull(restrictions, "restrictions");
  52. _expression = expression;
  53. _restrictions = restrictions;
  54. }
  55. /// <summary>
  56. /// Initializes a new instance of the <see cref="DynamicMetaObject"/> class.
  57. /// </summary>
  58. /// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param>
  59. /// <param name="restrictions">The set of binding restrictions under which the binding is valid.</param>
  60. /// <param name="value">The runtime value represented by the <see cref="DynamicMetaObject"/>.</param>
  61. public DynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value)
  62. : this(expression, restrictions) {
  63. _value = value;
  64. _hasValue = true;
  65. }
  66. /// <summary>
  67. /// The expression representing the <see cref="DynamicMetaObject"/> during the dynamic binding process.
  68. /// </summary>
  69. public Expression Expression {
  70. get {
  71. return _expression;
  72. }
  73. }
  74. /// <summary>
  75. /// The set of binding restrictions under which the binding is valid.
  76. /// </summary>
  77. public BindingRestrictions Restrictions {
  78. get {
  79. return _restrictions;
  80. }
  81. }
  82. /// <summary>
  83. /// The runtime value represented by this <see cref="DynamicMetaObject"/>.
  84. /// </summary>
  85. public object Value {
  86. get {
  87. return _value;
  88. }
  89. }
  90. /// <summary>
  91. /// Gets a value indicating whether the <see cref="DynamicMetaObject"/> has the runtime value.
  92. /// </summary>
  93. public bool HasValue {
  94. get {
  95. return _hasValue;
  96. }
  97. }
  98. /// <summary>
  99. /// Gets the <see cref="Type"/> of the runtime value or null if the <see cref="DynamicMetaObject"/> has no value associated with it.
  100. /// </summary>
  101. public Type RuntimeType {
  102. get {
  103. if (_hasValue) {
  104. Type ct = Expression.Type;
  105. // valuetype at compile tyme, type cannot change.
  106. if (ct.IsValueType) {
  107. return ct;
  108. }
  109. if (_value != null) {
  110. return _value.GetType();
  111. } else {
  112. return null;
  113. }
  114. } else {
  115. return null;
  116. }
  117. }
  118. }
  119. /// <summary>
  120. /// Gets the limit type of the <see cref="DynamicMetaObject"/>.
  121. /// </summary>
  122. /// <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>
  123. public Type LimitType {
  124. get {
  125. return RuntimeType ?? Expression.Type;
  126. }
  127. }
  128. /// <summary>
  129. /// Performs the binding of the dynamic conversion operation.
  130. /// </summary>
  131. /// <param name="binder">An instance of the <see cref="ConvertBinder"/> that represents the details of the dynamic operation.</param>
  132. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  133. public virtual DynamicMetaObject BindConvert(ConvertBinder binder) {
  134. ContractUtils.RequiresNotNull(binder, "binder");
  135. return binder.FallbackConvert(this);
  136. }
  137. /// <summary>
  138. /// Performs the binding of the dynamic get member operation.
  139. /// </summary>
  140. /// <param name="binder">An instance of the <see cref="GetMemberBinder"/> that represents the details of the dynamic operation.</param>
  141. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  142. public virtual DynamicMetaObject BindGetMember(GetMemberBinder binder) {
  143. ContractUtils.RequiresNotNull(binder, "binder");
  144. return binder.FallbackGetMember(this);
  145. }
  146. /// <summary>
  147. /// Performs the binding of the dynamic set member operation.
  148. /// </summary>
  149. /// <param name="binder">An instance of the <see cref="SetMemberBinder"/> that represents the details of the dynamic operation.</param>
  150. /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set member operation.</param>
  151. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  152. public virtual DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) {
  153. ContractUtils.RequiresNotNull(binder, "binder");
  154. return binder.FallbackSetMember(this, value);
  155. }
  156. /// <summary>
  157. /// Performs the binding of the dynamic delete member operation.
  158. /// </summary>
  159. /// <param name="binder">An instance of the <see cref="DeleteMemberBinder"/> that represents the details of the dynamic operation.</param>
  160. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  161. public virtual DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) {
  162. ContractUtils.RequiresNotNull(binder, "binder");
  163. return binder.FallbackDeleteMember(this);
  164. }
  165. /// <summary>
  166. /// Performs the binding of the dynamic get index operation.
  167. /// </summary>
  168. /// <param name="binder">An instance of the <see cref="GetIndexBinder"/> that represents the details of the dynamic operation.</param>
  169. /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the get index operation.</param>
  170. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  171. public virtual DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) {
  172. ContractUtils.RequiresNotNull(binder, "binder");
  173. return binder.FallbackGetIndex(this, indexes);
  174. }
  175. /// <summary>
  176. /// Performs the binding of the dynamic set index operation.
  177. /// </summary>
  178. /// <param name="binder">An instance of the <see cref="SetIndexBinder"/> that represents the details of the dynamic operation.</param>
  179. /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the set index operation.</param>
  180. /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set index operation.</param>
  181. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  182. public virtual DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) {
  183. ContractUtils.RequiresNotNull(binder, "binder");
  184. return binder.FallbackSetIndex(this, indexes, value);
  185. }
  186. /// <summary>
  187. /// Performs the binding of the dynamic delete index operation.
  188. /// </summary>
  189. /// <param name="binder">An instance of the <see cref="DeleteIndexBinder"/> that represents the details of the dynamic operation.</param>
  190. /// <param name="indexes">An array of <see cref="DynamicMetaObject"/> instances - indexes for the delete index operation.</param>
  191. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  192. public virtual DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes) {
  193. ContractUtils.RequiresNotNull(binder, "binder");
  194. return binder.FallbackDeleteIndex(this, indexes);
  195. }
  196. /// <summary>
  197. /// Performs the binding of the dynamic invoke member operation.
  198. /// </summary>
  199. /// <param name="binder">An instance of the <see cref="InvokeMemberBinder"/> that represents the details of the dynamic operation.</param>
  200. /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>
  201. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  202. public virtual DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) {
  203. ContractUtils.RequiresNotNull(binder, "binder");
  204. return binder.FallbackInvokeMember(this, args);
  205. }
  206. /// <summary>
  207. /// Performs the binding of the dynamic invoke operation.
  208. /// </summary>
  209. /// <param name="binder">An instance of the <see cref="InvokeBinder"/> that represents the details of the dynamic operation.</param>
  210. /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke operation.</param>
  211. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  212. public virtual DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) {
  213. ContractUtils.RequiresNotNull(binder, "binder");
  214. return binder.FallbackInvoke(this, args);
  215. }
  216. /// <summary>
  217. /// Performs the binding of the dynamic create instance operation.
  218. /// </summary>
  219. /// <param name="binder">An instance of the <see cref="CreateInstanceBinder"/> that represents the details of the dynamic operation.</param>
  220. /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the create instance operation.</param>
  221. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  222. public virtual DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args) {
  223. ContractUtils.RequiresNotNull(binder, "binder");
  224. return binder.FallbackCreateInstance(this, args);
  225. }
  226. /// <summary>
  227. /// Performs the binding of the dynamic unary operation.
  228. /// </summary>
  229. /// <param name="binder">An instance of the <see cref="UnaryOperationBinder"/> that represents the details of the dynamic operation.</param>
  230. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  231. public virtual DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder) {
  232. ContractUtils.RequiresNotNull(binder, "binder");
  233. return binder.FallbackUnaryOperation(this);
  234. }
  235. /// <summary>
  236. /// Performs the binding of the dynamic binary operation.
  237. /// </summary>
  238. /// <param name="binder">An instance of the <see cref="BinaryOperationBinder"/> that represents the details of the dynamic operation.</param>
  239. /// <param name="arg">An instance of the <see cref="DynamicMetaObject"/> representing the right hand side of the binary operation.</param>
  240. /// <returns>The new <see cref="DynamicMetaObject"/> representing the result of the binding.</returns>
  241. public virtual DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg) {
  242. ContractUtils.RequiresNotNull(binder, "binder");
  243. return binder.FallbackBinaryOperation(this, arg);
  244. }
  245. /// <summary>
  246. /// Returns the enumeration of all dynamic member names.
  247. /// </summary>
  248. /// <returns>The list of dynamic member names.</returns>
  249. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  250. public virtual IEnumerable<string> GetDynamicMemberNames() {
  251. return new string[0];
  252. }
  253. /// <summary>
  254. /// Returns the list of expressions represented by the <see cref="DynamicMetaObject"/> instances.
  255. /// </summary>
  256. /// <param name="objects">An array of <see cref="DynamicMetaObject"/> instances to extract expressions from.</param>
  257. /// <returns>The array of expressions.</returns>
  258. internal static Expression[] GetExpressions(DynamicMetaObject[] objects) {
  259. ContractUtils.RequiresNotNull(objects, "objects");
  260. Expression[] res = new Expression[objects.Length];
  261. for (int i = 0; i < objects.Length; i++) {
  262. DynamicMetaObject mo = objects[i];
  263. ContractUtils.RequiresNotNull(mo, "objects");
  264. Expression expr = mo.Expression;
  265. ContractUtils.RequiresNotNull(expr, "objects");
  266. res[i] = expr;
  267. }
  268. return res;
  269. }
  270. /// <summary>
  271. /// Creates a meta-object for the specified object.
  272. /// </summary>
  273. /// <param name="value">The object to get a meta-object for.</param>
  274. /// <param name="expression">The expression representing this <see cref="DynamicMetaObject"/> during the dynamic binding process.</param>
  275. /// <returns>
  276. /// If the given object implements <see cref="IDynamicMetaObjectProvider"/> and is not a remote object from outside the current AppDomain,
  277. /// returns the object's specific meta-object returned by <see cref="IDynamicMetaObjectProvider.GetMetaObject"/>. Otherwise a plain new meta-object
  278. /// with no restrictions is created and returned.
  279. /// </returns>
  280. public static DynamicMetaObject Create(object value, Expression expression) {
  281. ContractUtils.RequiresNotNull(expression, "expression");
  282. IDynamicMetaObjectProvider ido = value as IDynamicMetaObjectProvider;
  283. #if !SILVERLIGHT
  284. if (ido != null && !RemotingServices.IsObjectOutOfAppDomain(value)) {
  285. #else
  286. if (ido != null) {
  287. #endif
  288. var idoMetaObject = ido.GetMetaObject(expression);
  289. if (idoMetaObject == null ||
  290. !idoMetaObject.HasValue ||
  291. idoMetaObject.Value == null ||
  292. (object)idoMetaObject.Expression != (object)expression) {
  293. throw Error.InvalidMetaObjectCreated(ido.GetType());
  294. }
  295. return idoMetaObject;
  296. } else {
  297. return new DynamicMetaObject(expression, BindingRestrictions.Empty, value);
  298. }
  299. }
  300. /// <summary>
  301. /// Creates a <see cref="DynamicMetaObject"/> to represent a binding exception.
  302. /// </summary>
  303. /// <param name="target">The target of dynamic operation whose binding failed.</param>
  304. /// <param name="args">An array of arguments for the dynamic operation whose binding failed.</param>
  305. /// <param name="exception">A type of the exception to be thrown to signal the binding failure.</param>
  306. /// <param name="exceptionArgs">A list of arguments for the exception constructor.</param>
  307. /// <returns>The new instance of <see cref="DynamicMetaObject"/> representing the binding error.</returns>
  308. public static DynamicMetaObject CreateThrow(DynamicMetaObject target, DynamicMetaObject[] args, Type exception, params object[] exceptionArgs) {
  309. return CreateThrow(
  310. target,
  311. args,
  312. exception,
  313. exceptionArgs != null ? exceptionArgs.Map<object, Expression>((arg) => Expression.Constant(arg)) : null
  314. );
  315. }
  316. /// <summary>
  317. /// Creates a <see cref="DynamicMetaObject"/> to represent a binding exception.
  318. /// </summary>
  319. /// <param name="target">The target of dynamic operation whose binding failed.</param>
  320. /// <param name="args">An array of arguments for the dynamic operation whose binding failed.</param>
  321. /// <param name="exception">A type of the exception to be thrown to signal the binding failure.</param>
  322. /// <param name="exceptionArgs">A list of arguments for the exception constructor.</param>
  323. /// <returns>The new instance of <see cref="DynamicMetaObject"/> representing the binding error.</returns>
  324. public static DynamicMetaObject CreateThrow(DynamicMetaObject target, DynamicMetaObject[] args, Type exception, params Expression[] exceptionArgs) {
  325. ContractUtils.RequiresNotNull(target, "target");
  326. ContractUtils.RequiresNotNull(exception, "exception");
  327. Type[] argTypes = exceptionArgs != null ? exceptionArgs.Map((arg) => arg.Type) : Type.EmptyTypes;
  328. ConstructorInfo constructor = exception.GetConstructor(argTypes);
  329. if (constructor == null) {
  330. throw new ArgumentException(Strings.TypeDoesNotHaveConstructorForTheSignature);
  331. }
  332. return new DynamicMetaObject(
  333. Expression.Throw(
  334. Expression.New(
  335. exception.GetConstructor(argTypes),
  336. exceptionArgs
  337. )
  338. ),
  339. target.Restrictions.Merge(BindingRestrictions.Combine(args))
  340. );
  341. }
  342. }
  343. }