Skip to content

Commit

Permalink
Backport fix dynamic object member access logic (sebastienros#1937)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Aug 10, 2024
1 parent 8ce657f commit eb00784
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 9 deletions.
46 changes: 46 additions & 0 deletions Jint.Tests.PublicInterface/InteropTests.Dynamic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,52 @@ public void CanAccessDynamicObject()
Assert.False(engine.Evaluate("test.ContainsKey('c')").AsBoolean());
}

[Fact]
public void ShouldAccessCustomDynamicObjectProperties()
{
var t = new DynamicType
{
["MemberKey"] = new MemberType
{
Field = 4
}
};
var e = new Engine().SetValue("dynamicObj", t);
Assert.Equal(4, ((dynamic) t).MemberKey.Field);
Assert.Equal(4, e.Evaluate("dynamicObj.MemberKey.Field"));
}

private class MemberType
{
public int Field;
}

private class DynamicType : DynamicObject
{
private readonly Dictionary<string, object> _data = new();

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_data.ContainsKey(binder.Name))
{
result = this[binder.Name];
return true;
}

return base.TryGetMember(binder, out result);
}

public object this[string key]
{
get
{
_data.TryGetValue(key, out var value);
return value;
}
set => _data[key] = value;
}
}

private class DynamicClass : DynamicObject
{
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ protected internal override JsValue? CustomValue
private JsValue DoGet(JsValue? thisObj)
{
var value = _reflectionAccessor.GetValue(_engine, _target, _propertyName);
var type = _reflectionAccessor.MemberType;
var type = _reflectionAccessor.MemberType ?? value?.GetType();
return JsValue.FromObjectWithType(_engine, value, type);
}

Expand Down
4 changes: 1 addition & 3 deletions Jint/Runtime/Interop/Reflection/DynamicObjectAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ internal sealed class DynamicObjectAccessor : ReflectionAccessor
private JintSetMemberBinder? _setter;
private JintGetMemberBinder? _getter;

public DynamicObjectAccessor(
Type memberType,
PropertyInfo? indexer = null) : base(memberType, indexer)
public DynamicObjectAccessor() : base(memberType: null)
{
}

Expand Down
9 changes: 5 additions & 4 deletions Jint/Runtime/Interop/Reflection/ReflectionAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ namespace Jint.Runtime.Interop.Reflection;
/// </summary>
internal abstract class ReflectionAccessor
{
private readonly Type _memberType;
private readonly Type? _memberType;
private readonly PropertyInfo? _indexer;

public Type MemberType => _memberType;
public Type? MemberType => _memberType;

protected ReflectionAccessor(
Type memberType,
Type? memberType,
PropertyInfo? indexer = null)
{
_memberType = memberType;
Expand Down Expand Up @@ -114,7 +114,8 @@ public void SetValue(Engine engine, object target, string memberName, JsValue va

protected virtual object? ConvertValueToSet(Engine engine, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields)] object value)
{
return engine.TypeConverter.Convert(value, _memberType, CultureInfo.InvariantCulture);
var memberType = _memberType ?? value.GetType();
return engine.TypeConverter.Convert(value, memberType, CultureInfo.InvariantCulture);
}

public virtual PropertyDescriptor CreatePropertyDescriptor(Engine engine, object target, string memberName, bool enumerable = true)
Expand Down
2 changes: 1 addition & 1 deletion Jint/Runtime/Interop/TypeResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ private ReflectionAccessor ResolvePropertyDescriptorFactory(

if (typeof(DynamicObject).IsAssignableFrom(type))
{
return new DynamicObjectAccessor(type);
return new DynamicObjectAccessor();
}

var typeResolverMemberNameComparer = MemberNameComparer;
Expand Down

0 comments on commit eb00784

Please sign in to comment.