PageRenderTime 52ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting.Core/Actions/DynamicObject.cs

https://bitbucket.org/stefanrusek/xronos
C# | 622 lines | 302 code | 85 blank | 235 comment | 25 complexity | 21bc2f9814c6464b697f58387e6235b9 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.Diagnostics;
  17. #if CODEPLEX_40
  18. using System.Linq.Expressions;
  19. #else
  20. using Microsoft.Linq.Expressions;
  21. #endif
  22. using System.Reflection;
  23. #if CODEPLEX_40
  24. using System.Dynamic.Utils;
  25. #else
  26. using Microsoft.Scripting.Utils;
  27. #endif
  28. #if CODEPLEX_40
  29. namespace System.Dynamic {
  30. #else
  31. namespace Microsoft.Scripting {
  32. #endif
  33. /// <summary>
  34. /// Provides a simple class that can be inherited from to create an object with dynamic behavior
  35. /// at runtime. Subclasses can override the various binder methods (GetMember, SetMember, Call, etc...)
  36. /// to provide custom behavior that will be invoked at runtime.
  37. ///
  38. /// If a method is not overridden then the DynamicObject does not directly support that behavior and
  39. /// the call site will determine how the binding should be performed.
  40. /// </summary>
  41. public class DynamicObject : IDynamicMetaObjectProvider {
  42. /// <summary>
  43. /// Enables derived types to create a new instance of DynamicObject. DynamicObject instances cannot be
  44. /// directly instantiated because they have no implementation of dynamic behavior.
  45. /// </summary>
  46. protected DynamicObject() {
  47. }
  48. #region Public Virtual APIs
  49. /// <summary>
  50. /// Provides the implementation of getting a member. Derived classes can override
  51. /// this method to customize behavior. When not overridden the call site requesting the
  52. /// binder determines the behavior.
  53. /// </summary>
  54. /// <param name="binder">The binder provided by the call site.</param>
  55. /// <param name="result">The result of the get operation.</param>
  56. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  57. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  58. public virtual bool TryGetMember(GetMemberBinder binder, out object result) {
  59. result = null;
  60. return false;
  61. }
  62. /// <summary>
  63. /// Provides the implementation of setting a member. Derived classes can override
  64. /// this method to customize behavior. When not overridden the call site requesting the
  65. /// binder determines the behavior.
  66. /// </summary>
  67. /// <param name="binder">The binder provided by the call site.</param>
  68. /// <param name="value">The value to set.</param>
  69. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  70. public virtual bool TrySetMember(SetMemberBinder binder, object value) {
  71. return false;
  72. }
  73. /// <summary>
  74. /// Provides the implementation of deleting a member. Derived classes can override
  75. /// this method to customize behavior. When not overridden the call site requesting the
  76. /// binder determines the behavior.
  77. /// </summary>
  78. /// <param name="binder">The binder provided by the call site.</param>
  79. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  80. public virtual bool TryDeleteMember(DeleteMemberBinder binder) {
  81. return false;
  82. }
  83. /// <summary>
  84. /// Provides the implementation of calling a member. Derived classes can override
  85. /// this method to customize behavior. When not overridden the call site requesting the
  86. /// binder determines the behavior.
  87. /// </summary>
  88. /// <param name="binder">The binder provided by the call site.</param>
  89. /// <param name="args">The arguments to be used for the invocation.</param>
  90. /// <param name="result">The result of the invocation.</param>
  91. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  92. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  93. public virtual bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) {
  94. result = null;
  95. return false;
  96. }
  97. /// <summary>
  98. /// Provides the implementation of converting the DynamicObject to another type. Derived classes
  99. /// can override this method to customize behavior. When not overridden the call site
  100. /// requesting the binder determines the behavior.
  101. /// </summary>
  102. /// <param name="binder">The binder provided by the call site.</param>
  103. /// <param name="result">The result of the conversion.</param>
  104. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  105. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  106. public virtual bool TryConvert(ConvertBinder binder, out object result) {
  107. result = null;
  108. return false;
  109. }
  110. /// <summary>
  111. /// Provides the implementation of creating an instance of the DynamicObject. Derived classes
  112. /// can override this method to customize behavior. When not overridden the call site requesting
  113. /// the binder determines the behavior.
  114. /// </summary>
  115. /// <param name="binder">The binder provided by the call site.</param>
  116. /// <param name="args">The arguments used for creation.</param>
  117. /// <param name="result">The created instance.</param>
  118. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  119. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  120. public virtual bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result) {
  121. result = null;
  122. return false;
  123. }
  124. /// <summary>
  125. /// Provides the implementation of invoking the DynamicObject. Derived classes can
  126. /// override this method to customize behavior. When not overridden the call site requesting
  127. /// the binder determines the behavior.
  128. /// </summary>
  129. /// <param name="binder">The binder provided by the call site.</param>
  130. /// <param name="args">The arguments to be used for the invocation.</param>
  131. /// <param name="result">The result of the invocation.</param>
  132. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  133. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  134. public virtual bool TryInvoke(InvokeBinder binder, object[] args, out object result) {
  135. result = null;
  136. return false;
  137. }
  138. /// <summary>
  139. /// Provides the implementation of performing a binary operation. Derived classes can
  140. /// override this method to customize behavior. When not overridden the call site requesting
  141. /// the binder determines the behavior.
  142. /// </summary>
  143. /// <param name="binder">The binder provided by the call site.</param>
  144. /// <param name="arg">The right operand for the operation.</param>
  145. /// <param name="result">The result of the operation.</param>
  146. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  147. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  148. public virtual bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) {
  149. result = null;
  150. return false;
  151. }
  152. /// <summary>
  153. /// Provides the implementation of performing a unary operation. Derived classes can
  154. /// override this method to customize behavior. When not overridden the call site requesting
  155. /// the binder determines the behavior.
  156. /// </summary>
  157. /// <param name="binder">The binder provided by the call site.</param>
  158. /// <param name="result">The result of the operation.</param>
  159. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  160. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  161. public virtual bool TryUnaryOperation(UnaryOperationBinder binder, out object result) {
  162. result = null;
  163. return false;
  164. }
  165. /// <summary>
  166. /// Provides the implementation of performing a get index operation. Derived classes can
  167. /// override this method to customize behavior. When not overridden the call site requesting
  168. /// the binder determines the behavior.
  169. /// </summary>
  170. /// <param name="binder">The binder provided by the call site.</param>
  171. /// <param name="indexes">The indexes to be used.</param>
  172. /// <param name="result">The result of the operation.</param>
  173. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  174. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  175. public virtual bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
  176. result = null;
  177. return false;
  178. }
  179. /// <summary>
  180. /// Provides the implementation of performing a set index operation. Derived classes can
  181. /// override this method to custmize behavior. When not overridden the call site requesting
  182. /// the binder determines the behavior.
  183. /// </summary>
  184. /// <param name="binder">The binder provided by the call site.</param>
  185. /// <param name="indexes">The indexes to be used.</param>
  186. /// <param name="value">The value to set.</param>
  187. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  188. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  189. public virtual bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) {
  190. return false;
  191. }
  192. /// <summary>
  193. /// Provides the implementation of performing a delete index operation. Derived classes
  194. /// can override this method to custmize behavior. When not overridden the call site
  195. /// requesting the binder determines the behavior.
  196. /// </summary>
  197. /// <param name="binder">The binder provided by the call site.</param>
  198. /// <param name="indexes">The indexes to be deleted.</param>
  199. /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
  200. public virtual bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes) {
  201. return false;
  202. }
  203. /// <summary>
  204. /// Returns the enumeration of all dynamic member names.
  205. /// </summary>
  206. /// <returns>The list of dynamic member names.</returns>
  207. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  208. public virtual System.Collections.Generic.IEnumerable<string> GetDynamicMemberNames() {
  209. return new string[0];
  210. }
  211. #endregion
  212. #region MetaDynamic
  213. private sealed class MetaDynamic : DynamicMetaObject {
  214. internal MetaDynamic(Expression expression, DynamicObject value)
  215. : base(expression, BindingRestrictions.Empty, value) {
  216. }
  217. public override System.Collections.Generic.IEnumerable<string> GetDynamicMemberNames()
  218. {
  219. return Value.GetDynamicMemberNames();
  220. }
  221. public override DynamicMetaObject BindGetMember(GetMemberBinder binder) {
  222. if (IsOverridden("TryGetMember")) {
  223. return CallMethodWithResult("TryGetMember", binder, NoArgs, (e) => binder.FallbackGetMember(this, e));
  224. }
  225. return base.BindGetMember(binder);
  226. }
  227. public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) {
  228. if (IsOverridden("TrySetMember")) {
  229. return CallMethodReturnLast("TrySetMember", binder, GetArgs(value), (e) => binder.FallbackSetMember(this, value, e));
  230. }
  231. return base.BindSetMember(binder, value);
  232. }
  233. public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) {
  234. if (IsOverridden("TryDeleteMember")) {
  235. return CallMethodNoResult("TryDeleteMember", binder, NoArgs, (e) => binder.FallbackDeleteMember(this, e));
  236. }
  237. return base.BindDeleteMember(binder);
  238. }
  239. public override DynamicMetaObject BindConvert(ConvertBinder binder) {
  240. if (IsOverridden("TryConvert")) {
  241. return CallMethodWithResult("TryConvert", binder, NoArgs, (e) => binder.FallbackConvert(this, e));
  242. }
  243. return base.BindConvert(binder);
  244. }
  245. public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) {
  246. if (IsOverridden("TryInvokeMember")) {
  247. return CallMethodWithResult("TryInvokeMember", binder, GetArgArray(args), (e) => binder.FallbackInvokeMember(this, args, e));
  248. } else if (IsOverridden("TryGetMember")) {
  249. // Generate a tree like:
  250. //
  251. // {
  252. // object result;
  253. // TryGetMember(payload, out result) ? FallbackInvoke(result) : fallbackResult
  254. // }
  255. //
  256. // Then it calls FallbackInvokeMember with this tree as the
  257. // "error", giving the language the option of using this
  258. // tree or doing .NET binding.
  259. //
  260. return CallMethodWithResult(
  261. "TryGetMember", new GetBinderAdapter(binder), NoArgs,
  262. (e) => binder.FallbackInvokeMember(this, args, e),
  263. (e) => binder.FallbackInvoke(e, args, null)
  264. );
  265. }
  266. return base.BindInvokeMember(binder, args);
  267. }
  268. public override DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args) {
  269. if (IsOverridden("TryCreateInstance")) {
  270. return CallMethodWithResult("TryCreateInstance", binder, GetArgArray(args), (e) => binder.FallbackCreateInstance(this, args, e));
  271. }
  272. return base.BindCreateInstance(binder, args);
  273. }
  274. public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) {
  275. if (IsOverridden("TryInvoke")) {
  276. return CallMethodWithResult("TryInvoke", binder, GetArgArray(args), (e) => binder.FallbackInvoke(this, args, e));
  277. }
  278. return base.BindInvoke(binder, args);
  279. }
  280. public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg) {
  281. if (IsOverridden("TryBinaryOperation")) {
  282. return CallMethodWithResult("TryBinaryOperation", binder, GetArgs(arg), (e) => binder.FallbackBinaryOperation(this, arg, e));
  283. }
  284. return base.BindBinaryOperation(binder, arg);
  285. }
  286. public override DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder) {
  287. if (IsOverridden("TryUnaryOperation")) {
  288. return CallMethodWithResult("TryUnaryOperation", binder, NoArgs, (e) => binder.FallbackUnaryOperation(this, e));
  289. }
  290. return base.BindUnaryOperation(binder);
  291. }
  292. public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) {
  293. if (IsOverridden("TryGetIndex")) {
  294. return CallMethodWithResult("TryGetIndex", binder, GetArgArray(indexes), (e) => binder.FallbackGetIndex(this, indexes, e));
  295. }
  296. return base.BindGetIndex(binder, indexes);
  297. }
  298. public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) {
  299. if (IsOverridden("TrySetIndex")) {
  300. return CallMethodReturnLast("TrySetIndex", binder, GetArgArray(indexes, value), (e) => binder.FallbackSetIndex(this, indexes, value, e));
  301. }
  302. return base.BindSetIndex(binder, indexes, value);
  303. }
  304. public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes) {
  305. if (IsOverridden("TryDeleteIndex")) {
  306. return CallMethodNoResult("TryDeleteIndex", binder, GetArgArray(indexes), (e) => binder.FallbackDeleteIndex(this, indexes, e));
  307. }
  308. return base.BindDeleteIndex(binder, indexes);
  309. }
  310. private delegate DynamicMetaObject Fallback(DynamicMetaObject errorSuggestion);
  311. private readonly static Expression[] NoArgs = new Expression[0];
  312. private static Expression[] GetArgs(params DynamicMetaObject[] args) {
  313. Expression[] paramArgs = DynamicMetaObject.GetExpressions(args);
  314. for (int i = 0; i < paramArgs.Length; i++) {
  315. paramArgs[i] = Expression.Convert(args[i].Expression, typeof(object));
  316. }
  317. return paramArgs;
  318. }
  319. private static Expression[] GetArgArray(DynamicMetaObject[] args) {
  320. return new[] { Expression.NewArrayInit(typeof(object), GetArgs(args)) };
  321. }
  322. private static Expression[] GetArgArray(DynamicMetaObject[] args, DynamicMetaObject value) {
  323. return new Expression[] {
  324. Expression.NewArrayInit(typeof(object), GetArgs(args)),
  325. Expression.Convert(value.Expression, typeof(object))
  326. };
  327. }
  328. private static ConstantExpression Constant(DynamicMetaObjectBinder binder) {
  329. Type t = binder.GetType();
  330. while (!t.IsVisible) {
  331. t = t.BaseType;
  332. }
  333. return Expression.Constant(binder, t);
  334. }
  335. /// <summary>
  336. /// Helper method for generating a MetaObject which calls a
  337. /// specific method on Dynamic that returns a result
  338. /// </summary>
  339. private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback) {
  340. return CallMethodWithResult(methodName, binder, args, fallback, null);
  341. }
  342. /// <summary>
  343. /// Helper method for generating a MetaObject which calls a
  344. /// specific method on Dynamic that returns a result
  345. /// </summary>
  346. private DynamicMetaObject CallMethodWithResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback, Fallback fallbackInvoke) {
  347. //
  348. // First, call fallback to do default binding
  349. // This produces either an error or a call to a .NET member
  350. //
  351. DynamicMetaObject fallbackResult = fallback(null);
  352. //
  353. // Build a new expression like:
  354. // {
  355. // object result;
  356. // TryGetMember(payload, out result) ? fallbackInvoke(result) : fallbackResult
  357. // }
  358. //
  359. var result = Expression.Parameter(typeof(object), null);
  360. var callArgs = new Expression[args.Length + 2];
  361. Array.Copy(args, 0, callArgs, 1, args.Length);
  362. callArgs[0] = Constant(binder);
  363. callArgs[callArgs.Length - 1] = result;
  364. var resultMO = new DynamicMetaObject(result, BindingRestrictions.Empty);
  365. if (fallbackInvoke != null) {
  366. resultMO = fallbackInvoke(resultMO);
  367. }
  368. var callDynamic = new DynamicMetaObject(
  369. Expression.Block(
  370. new[] { result },
  371. Expression.Condition(
  372. Expression.Call(
  373. GetLimitedSelf(),
  374. typeof(DynamicObject).GetMethod(methodName),
  375. callArgs
  376. ),
  377. resultMO.Expression,
  378. DynamicMetaObjectBinder.Convert(fallbackResult.Expression, typeof(object))
  379. )
  380. ),
  381. GetRestrictions().Merge(resultMO.Restrictions).Merge(fallbackResult.Restrictions)
  382. );
  383. //
  384. // Now, call fallback again using our new MO as the error
  385. // When we do this, one of two things can happen:
  386. // 1. Binding will succeed, and it will ignore our call to
  387. // the dynamic method, OR
  388. // 2. Binding will fail, and it will use the MO we created
  389. // above.
  390. //
  391. return fallback(callDynamic);
  392. }
  393. /// <summary>
  394. /// Helper method for generating a MetaObject which calls a
  395. /// specific method on Dynamic, but uses one of the arguments for
  396. /// the result.
  397. /// </summary>
  398. private DynamicMetaObject CallMethodReturnLast(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback) {
  399. //
  400. // First, call fallback to do default binding
  401. // This produces either an error or a call to a .NET member
  402. //
  403. DynamicMetaObject fallbackResult = fallback(null);
  404. //
  405. // Build a new expression like:
  406. // {
  407. // object result;
  408. // TrySetMember(payload, result = value) ? result : fallbackResult
  409. // }
  410. //
  411. var result = Expression.Parameter(typeof(object), null);
  412. var callArgs = args.AddFirst(Constant(binder));
  413. callArgs[args.Length] = Expression.Assign(result, callArgs[args.Length]);
  414. var callDynamic = new DynamicMetaObject(
  415. Expression.Block(
  416. new[] { result },
  417. Expression.Condition(
  418. Expression.Call(
  419. GetLimitedSelf(),
  420. typeof(DynamicObject).GetMethod(methodName),
  421. callArgs
  422. ),
  423. result,
  424. DynamicMetaObjectBinder.Convert(fallbackResult.Expression, typeof(object))
  425. )
  426. ),
  427. GetRestrictions().Merge(fallbackResult.Restrictions)
  428. );
  429. //
  430. // Now, call fallback again using our new MO as the error
  431. // When we do this, one of two things can happen:
  432. // 1. Binding will succeed, and it will ignore our call to
  433. // the dynamic method, OR
  434. // 2. Binding will fail, and it will use the MO we created
  435. // above.
  436. //
  437. return fallback(callDynamic);
  438. }
  439. /// <summary>
  440. /// Helper method for generating a MetaObject which calls a
  441. /// specific method on Dynamic, but uses one of the arguments for
  442. /// the result.
  443. /// </summary>
  444. private DynamicMetaObject CallMethodNoResult(string methodName, DynamicMetaObjectBinder binder, Expression[] args, Fallback fallback) {
  445. //
  446. // First, call fallback to do default binding
  447. // This produces either an error or a call to a .NET member
  448. //
  449. DynamicMetaObject fallbackResult = fallback(null);
  450. //
  451. // Build a new expression like:
  452. // TryDeleteMember(payload) ? null : fallbackResult
  453. //
  454. var callDynamic = new DynamicMetaObject(
  455. Expression.Condition(
  456. Expression.Call(
  457. GetLimitedSelf(),
  458. typeof(DynamicObject).GetMethod(methodName),
  459. args.AddFirst(Constant(binder))
  460. ),
  461. Expression.Constant(null),
  462. DynamicMetaObjectBinder.Convert(fallbackResult.Expression, typeof(object))
  463. ),
  464. GetRestrictions().Merge(fallbackResult.Restrictions)
  465. );
  466. //
  467. // Now, call fallback again using our new MO as the error
  468. // When we do this, one of two things can happen:
  469. // 1. Binding will succeed, and it will ignore our call to
  470. // the dynamic method, OR
  471. // 2. Binding will fail, and it will use the MO we created
  472. // above.
  473. //
  474. return fallback(callDynamic);
  475. }
  476. /// <summary>
  477. /// Checks if the derived type has overridden the specified method. If there is no
  478. /// implementation for the method provided then Dynamic falls back to the base class
  479. /// behavior which lets the call site determine how the binder is performed.
  480. /// </summary>
  481. private bool IsOverridden(string method) {
  482. var methods = Value.GetType().GetMember(method, MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance);
  483. foreach (MethodInfo mi in methods) {
  484. if (mi.DeclaringType != typeof(DynamicObject) && mi.GetBaseDefinition().DeclaringType == typeof(DynamicObject)) {
  485. return true;
  486. }
  487. }
  488. return false;
  489. }
  490. /// <summary>
  491. /// Returns a Restrictions object which includes our current restrictions merged
  492. /// with a restriction limiting our type
  493. /// </summary>
  494. private BindingRestrictions GetRestrictions() {
  495. Debug.Assert(Restrictions == BindingRestrictions.Empty, "We don't merge, restrictions are always empty");
  496. return BindingRestrictions.GetTypeRestriction(this);
  497. }
  498. /// <summary>
  499. /// Returns our Expression converted to our known LimitType
  500. /// </summary>
  501. private Expression GetLimitedSelf() {
  502. if (Expression.Type == LimitType) {
  503. return Expression;
  504. }
  505. return Expression.Convert(Expression, LimitType);
  506. }
  507. private new DynamicObject Value {
  508. get {
  509. return (DynamicObject)base.Value;
  510. }
  511. }
  512. // It is okay to throw NotSupported from this binder. This object
  513. // is only used by DynamicObject.GetMember--it is not expected to
  514. // (and cannot) implement binding semantics. It is just so the DO
  515. // can use the Name and IgnoreCase properties.
  516. private sealed class GetBinderAdapter : GetMemberBinder {
  517. internal GetBinderAdapter(InvokeMemberBinder binder)
  518. : base(binder.Name, binder.IgnoreCase) {
  519. }
  520. public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) {
  521. throw new NotSupportedException();
  522. }
  523. }
  524. }
  525. #endregion
  526. #region IDynamicMetaObjectProvider Members
  527. /// <summary>
  528. /// The provided MetaObject will dispatch to the Dynamic virtual methods.
  529. /// The object can be encapsulated inside of another MetaObject to
  530. /// provide custom behavior for individual actions.
  531. /// </summary>
  532. public virtual DynamicMetaObject GetMetaObject(Expression parameter) {
  533. return new MetaDynamic(parameter, this);
  534. }
  535. #endregion
  536. }
  537. }