IndexDescriptor.cs 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. using System;
  2. using System.Globalization;
  3. using System.Linq;
  4. using System.Reflection;
  5. using Jint.Native;
  6. namespace Jint.Runtime.Descriptors.Specialized
  7. {
  8. public sealed class IndexDescriptor : PropertyDescriptor
  9. {
  10. private readonly Engine _engine;
  11. private readonly object _key;
  12. private readonly object _item;
  13. private readonly PropertyInfo _indexer;
  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
  20. .GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
  21. .Where(x => x.GetIndexParameters().Length == 1);
  22. // try to find first indexer having either public getter or setter with matching argument type
  23. foreach (var indexer in indexers)
  24. {
  25. if (indexer.GetGetMethod() != null || indexer.GetSetMethod() != null)
  26. {
  27. var paramType = indexer.GetIndexParameters()[0].ParameterType;
  28. if (_engine.ClrTypeConverter.TryConvert(key, paramType, CultureInfo.InvariantCulture, out _key))
  29. {
  30. _indexer = indexer;
  31. break;
  32. }
  33. }
  34. }
  35. // throw if no indexer found
  36. if (_indexer == null)
  37. {
  38. throw new InvalidOperationException("No matching indexer found.");
  39. }
  40. Writable = true;
  41. }
  42. public IndexDescriptor(Engine engine, string key, object item)
  43. : this(engine, item.GetType(), key, item)
  44. {
  45. }
  46. public override JsValue? Value
  47. {
  48. get
  49. {
  50. var getter = _indexer.GetGetMethod();
  51. if (getter == null)
  52. {
  53. throw new InvalidOperationException("Indexer has no public getter.");
  54. }
  55. object[] parameters = { _key };
  56. return JsValue.FromObject(_engine, getter.Invoke(_item, parameters));
  57. }
  58. set
  59. {
  60. var setter = _indexer.GetSetMethod();
  61. if (setter == null)
  62. {
  63. throw new InvalidOperationException("Indexer has no public setter.");
  64. }
  65. object[] parameters = { _key, value.HasValue ? value.Value.ToObject() : null };
  66. setter.Invoke(_item, parameters);
  67. }
  68. }
  69. }
  70. }