IndexDescriptor.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. using System;
  2. using System.Globalization;
  3. using System.Reflection;
  4. using Jint.Native;
  5. namespace Jint.Runtime.Descriptors.Specialized
  6. {
  7. public sealed class IndexDescriptor : PropertyDescriptor
  8. {
  9. private readonly Engine _engine;
  10. private readonly object _key;
  11. private readonly object _item;
  12. private readonly PropertyInfo _indexer;
  13. private readonly MethodInfo _containsKey;
  14. public IndexDescriptor(Engine engine, Type targetType, string key, object item)
  15. {
  16. _engine = engine;
  17. _item = item;
  18. // get all instance indexers with exactly 1 argument
  19. var indexers = targetType.GetProperties();
  20. // try to find first indexer having either public getter or setter with matching argument type
  21. foreach (var indexer in indexers)
  22. {
  23. if (indexer.GetIndexParameters().Length != 1) continue;
  24. if (indexer.GetGetMethod() != null || indexer.GetSetMethod() != null)
  25. {
  26. var paramType = indexer.GetIndexParameters()[0].ParameterType;
  27. if (_engine.ClrTypeConverter.TryConvert(key, paramType, CultureInfo.InvariantCulture, out _key))
  28. {
  29. _indexer = indexer;
  30. // get contains key method to avoid index exception being thrown in dictionaries
  31. _containsKey = targetType.GetMethod("ContainsKey", new Type[] { paramType });
  32. break;
  33. }
  34. }
  35. }
  36. // throw if no indexer found
  37. if (_indexer == null)
  38. {
  39. throw new InvalidOperationException("No matching indexer found.");
  40. }
  41. Writable = true;
  42. }
  43. public IndexDescriptor(Engine engine, string key, object item)
  44. : this(engine, item.GetType(), key, item)
  45. {
  46. }
  47. public override JsValue Value
  48. {
  49. get
  50. {
  51. var getter = _indexer.GetGetMethod();
  52. if (getter == null)
  53. {
  54. throw new InvalidOperationException("Indexer has no public getter.");
  55. }
  56. object[] parameters = { _key };
  57. if (_containsKey != null)
  58. {
  59. if ((_containsKey.Invoke(_item, parameters) as bool?) != true)
  60. {
  61. return JsValue.Undefined;
  62. }
  63. }
  64. try
  65. {
  66. return JsValue.FromObject(_engine, getter.Invoke(_item, parameters));
  67. }
  68. catch
  69. {
  70. return JsValue.Undefined;
  71. }
  72. }
  73. set
  74. {
  75. var setter = _indexer.GetSetMethod();
  76. if (setter == null)
  77. {
  78. throw new InvalidOperationException("Indexer has no public setter.");
  79. }
  80. object[] parameters = { _key, value != null ? value.ToObject() : null };
  81. setter.Invoke(_item, parameters);
  82. }
  83. }
  84. }
  85. }