2
0

ReflectionAccessor.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. using System.Globalization;
  2. using System.Reflection;
  3. using Jint.Extensions;
  4. using Jint.Native;
  5. using Jint.Runtime.Descriptors;
  6. using Jint.Runtime.Descriptors.Specialized;
  7. namespace Jint.Runtime.Interop.Reflection
  8. {
  9. /// <summary>
  10. /// Strategy to read and write CLR object properties and fields.
  11. /// </summary>
  12. internal abstract class ReflectionAccessor
  13. {
  14. private readonly Type _memberType;
  15. private readonly object? _memberName;
  16. private readonly PropertyInfo? _indexer;
  17. protected ReflectionAccessor(
  18. Type memberType,
  19. object? memberName,
  20. PropertyInfo? indexer = null)
  21. {
  22. _memberType = memberType;
  23. _memberName = memberName;
  24. _indexer = indexer;
  25. }
  26. public abstract bool Writable { get; }
  27. protected abstract object? DoGetValue(object target);
  28. protected abstract void DoSetValue(object target, object? value);
  29. public object? GetValue(Engine engine, object target)
  30. {
  31. var constantValue = ConstantValue;
  32. if (constantValue is not null)
  33. {
  34. return constantValue;
  35. }
  36. // first check indexer so we don't confuse inherited properties etc
  37. var value = TryReadFromIndexer(target);
  38. if (value is null)
  39. {
  40. try
  41. {
  42. value = DoGetValue(target);
  43. }
  44. catch (TargetInvocationException tie)
  45. {
  46. ExceptionHelper.ThrowMeaningfulException(engine, tie);
  47. }
  48. }
  49. return value;
  50. }
  51. protected virtual JsValue? ConstantValue => null;
  52. private object? TryReadFromIndexer(object target)
  53. {
  54. var getter = _indexer?.GetGetMethod();
  55. if (getter is null)
  56. {
  57. return null;
  58. }
  59. try
  60. {
  61. object[] parameters = { _memberName! };
  62. return getter.Invoke(target, parameters);
  63. }
  64. catch
  65. {
  66. return null;
  67. }
  68. }
  69. public void SetValue(Engine engine, object target, JsValue value)
  70. {
  71. object? converted;
  72. if (_memberType == typeof(JsValue))
  73. {
  74. converted = value;
  75. }
  76. else if (!ReflectionExtensions.TryConvertViaTypeCoercion(_memberType, engine.Options.Interop.ValueCoercion, value, out converted))
  77. {
  78. // attempt to convert the JsValue to the target type
  79. converted = value.ToObject();
  80. if (converted != null && converted.GetType() != _memberType)
  81. {
  82. converted = ConvertValueToSet(engine, converted);
  83. }
  84. }
  85. try
  86. {
  87. DoSetValue(target, converted);
  88. }
  89. catch (TargetInvocationException exception)
  90. {
  91. ExceptionHelper.ThrowMeaningfulException(engine, exception);
  92. }
  93. }
  94. protected virtual object? ConvertValueToSet(Engine engine, object value)
  95. {
  96. return engine.ClrTypeConverter.Convert(value, _memberType, CultureInfo.InvariantCulture);
  97. }
  98. public virtual PropertyDescriptor CreatePropertyDescriptor(Engine engine, object target, bool enumerable = true)
  99. {
  100. return new ReflectionDescriptor(engine, this, target, enumerable);
  101. }
  102. }
  103. }