123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- using System;
- using System.Globalization;
- using System.Reflection;
- using Jint.Native;
- using Jint.Runtime.Descriptors;
- using Jint.Runtime.Descriptors.Specialized;
- namespace Jint.Runtime.Interop.Reflection
- {
- /// <summary>
- /// Strategy to read and write CLR object properties and fields.
- /// </summary>
- internal abstract class ReflectionAccessor
- {
- private readonly Type _memberType;
- private readonly object _memberName;
- private readonly PropertyInfo _indexer;
- protected ReflectionAccessor(
- Type memberType,
- object memberName,
- PropertyInfo indexer = null)
- {
- _memberType = memberType;
- _memberName = memberName;
- _indexer = indexer;
- }
- public abstract bool Writable { get; }
- protected abstract object DoGetValue(object target);
- protected abstract void DoSetValue(object target, object value);
- public object GetValue(Engine engine, object target)
- {
- var constantValue = ConstantValue;
- if (constantValue is not null)
- {
- return constantValue;
- }
-
- // first check indexer so we don't confuse inherited properties etc
- var value = TryReadFromIndexer(target);
- if (value is null)
- {
- try
- {
- value = DoGetValue(target);
- }
- catch (TargetInvocationException tie)
- {
- switch (tie.InnerException)
- {
- case ArgumentOutOfRangeException _:
- case IndexOutOfRangeException _:
- case InvalidOperationException _:
- case NotSupportedException _:
- return JsValue.Undefined;
- }
- ExceptionHelper.ThrowMeaningfulException(engine, tie);
- }
- }
- return value;
- }
- protected virtual JsValue ConstantValue => null;
- private object TryReadFromIndexer(object target)
- {
- var getter = _indexer?.GetGetMethod();
- if (getter is null)
- {
- return null;
- }
- try
- {
- object[] parameters = { _memberName };
- return getter.Invoke(target, parameters);
- }
- catch
- {
- return null;
- }
- }
- public void SetValue(Engine engine, object target, JsValue value)
- {
- object converted;
- if (_memberType == typeof(JsValue))
- {
- converted = value;
- }
- else
- {
- // attempt to convert the JsValue to the target type
- converted = value.ToObject();
- if (converted != null && converted.GetType() != _memberType)
- {
- converted = ConvertValueToSet(engine, converted);
- }
- }
- try
- {
- DoSetValue(target, converted);
- }
- catch (TargetInvocationException exception)
- {
- ExceptionHelper.ThrowMeaningfulException(engine, exception);
- }
- }
- protected virtual object ConvertValueToSet(Engine engine, object value)
- {
- return engine.ClrTypeConverter.Convert(value, _memberType, CultureInfo.InvariantCulture);
- }
- public virtual PropertyDescriptor CreatePropertyDescriptor(Engine engine, object target)
- {
- return new ReflectionDescriptor(engine, this, target);
- }
- }
- }
|