Переглянути джерело

Improve interop finding of properties in derived types (#1969)

mspertus 10 місяців тому
батько
коміт
e67e58a00c

+ 41 - 0
Jint.Tests/Runtime/InteropTests.cs

@@ -3624,4 +3624,45 @@ try {
         engine.SetValue("c", new Circle(12.34));
         engine.SetValue("c", new Circle(12.34));
         engine.Evaluate("JSON.stringify(c)").ToString().Should().Be("{\"Radius\":12.34,\"Color\":0,\"Id\":123}");
         engine.Evaluate("JSON.stringify(c)").ToString().Should().Be("{\"Radius\":12.34,\"Color\":0,\"Id\":123}");
     }
     }
+
+    public class Animal
+    {
+        public virtual string name { get; set; } = "animal";
+    }
+
+    public class Elephant : Animal
+    {
+        public override string name { get; set; } = "elephant";
+        public int earSize = 5;
+    }
+
+    public class Lion : Animal
+    {
+        public override string name { get; set; } = "lion";
+        public int maneLength = 10;
+    }
+
+    public class Zoo
+    {
+        public Animal king { get => (new Animal[] { new Lion() })[0]; }
+        public Animal[] animals { get => new Animal[] { new Lion(), new Elephant() }; }
+    }
+
+    [Fact]
+    public void CanFindDerivedPropertiesFail() // Fails in 4.01 but success in 2.11
+    {
+        var engine = new Engine();
+        engine.SetValue("zoo", new Zoo());
+        var kingManeLength = engine.Evaluate("zoo.King.maneLength");
+        Assert.Equal(10, kingManeLength.AsNumber());
+    }
+
+    [Fact]
+    public void CanFindDerivedPropertiesSucceed() // Similar case that continues to succeed
+    {
+        var engine = new Engine();
+        engine.SetValue("zoo", new Zoo());
+        var lionManeLength = engine.Evaluate("zoo.animals[0].maneLength");
+        Assert.Equal(10, lionManeLength.AsNumber());
+    }
 }
 }

+ 4 - 0
Jint/Runtime/Interop/ObjectWrapper.cs

@@ -364,6 +364,10 @@ public class ObjectWrapper : ObjectInstance, IObjectWrapper, IEquatable<ObjectWr
         }
         }
 
 
         var accessor = _engine.Options.Interop.TypeResolver.GetAccessor(_engine, ClrType, member, mustBeReadable, mustBeWritable);
         var accessor = _engine.Options.Interop.TypeResolver.GetAccessor(_engine, ClrType, member, mustBeReadable, mustBeWritable);
+        if (accessor == ConstantValueAccessor.NullAccessor && ClrType != Target.GetType())
+        {
+            accessor = _engine.Options.Interop.TypeResolver.GetAccessor(_engine, Target.GetType(), member, mustBeReadable, mustBeWritable);
+        }
         var descriptor = accessor.CreatePropertyDescriptor(_engine, Target, member, enumerable: !isDictionary);
         var descriptor = accessor.CreatePropertyDescriptor(_engine, Target, member, enumerable: !isDictionary);
         if (!isDictionary
         if (!isDictionary
             && !ReferenceEquals(descriptor, PropertyDescriptor.Undefined)
             && !ReferenceEquals(descriptor, PropertyDescriptor.Undefined)