Browse Source

Prefer indexing and custom properties over indexer property (#773)

Marko Lahma 5 years ago
parent
commit
24cda031a8

+ 12 - 6
Jint.Tests/Runtime/Domain/Company.cs

@@ -6,7 +6,11 @@ namespace Jint.Tests.Runtime.Domain
     public class Company : ICompany, IComparable<ICompany>
     public class Company : ICompany, IComparable<ICompany>
     {
     {
         private string _name;
         private string _name;
-        private readonly Dictionary<string, string> _dictionary = new Dictionary<string, string>();
+
+        private readonly Dictionary<string, string> _dictionary = new Dictionary<string, string>()
+        {
+            {"key", "value"}
+        };
 
 
         public Company(string name)
         public Company(string name)
         {
         {
@@ -15,19 +19,21 @@ namespace Jint.Tests.Runtime.Domain
 
 
         string ICompany.Name
         string ICompany.Name
         {
         {
-            get { return _name; }
-            set { _name = value; }
+            get => _name;
+            set => _name = value;
         }
         }
 
 
         string ICompany.this[string key]
         string ICompany.this[string key]
         {
         {
-            get { return _dictionary[key]; }
-            set { _dictionary[key] = value; }
+            get => _dictionary[key];
+            set => _dictionary[key] = value;
         }
         }
 
 
+        public string Item => "item thingie";
+
         int IComparable<ICompany>.CompareTo(ICompany other)
         int IComparable<ICompany>.CompareTo(ICompany other)
         {
         {
             return string.Compare(_name, other.Name, StringComparison.CurrentCulture);
             return string.Compare(_name, other.Name, StringComparison.CurrentCulture);
         }
         }
     }
     }
-}
+}

+ 33 - 1
Jint.Tests/Runtime/InteropTests.cs

@@ -8,7 +8,6 @@ using System.Reflection;
 using Jint.Native;
 using Jint.Native;
 using Jint.Native.Array;
 using Jint.Native.Array;
 using Jint.Native.Object;
 using Jint.Native.Object;
-using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 using Jint.Runtime.Interop;
 using Jint.Tests.Runtime.Converters;
 using Jint.Tests.Runtime.Converters;
 using Jint.Tests.Runtime.Domain;
 using Jint.Tests.Runtime.Domain;
@@ -56,6 +55,39 @@ namespace Jint.Tests.Runtime
             ");
             ");
         }
         }
 
 
+        [Fact]
+        public void CanAccessMemberNamedItem()
+        {
+            _engine.Execute(@"
+                    function item2(arg) {
+                        return arg.item2
+                    }
+                    function item1(arg) {
+                        return arg.item
+                    }
+                    function item3(arg) {
+                        return arg.Item
+                    }
+            ");
+
+            var argument = new Dictionary<string, object>
+            {
+                {"item2", "item2 value"},
+                {"item", "item value"},
+                {"Item", "Item value"}
+            };
+
+            Assert.Equal("item2 value", _engine.Invoke("item2", argument));
+            Assert.Equal("item value", _engine.Invoke("item1", argument));
+            Assert.Equal("Item value", _engine.Invoke("item3", argument));
+
+            var company = new Company("Acme Ltd");
+            _engine.SetValue("c", company);
+            Assert.Equal("item thingie", _engine.Execute("c.Item").GetCompletionValue());
+            Assert.Equal("item thingie", _engine.Execute("c.item").GetCompletionValue());
+            Assert.Equal("value", _engine.Execute("c['key']").GetCompletionValue());
+        }
+
         [Fact]
         [Fact]
         public void DelegatesCanBeSet()
         public void DelegatesCanBeSet()
         {
         {

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

@@ -201,11 +201,13 @@ namespace Jint.Runtime.Interop
             // properties and fields cannot be numbers
             // properties and fields cannot be numbers
             if (!isNumber)
             if (!isNumber)
             {
             {
-                // look for a property
+                // look for a property, bit be wary of indexers, we don't want indexers which have name "Item" to take precedence
                 PropertyInfo property = null;
                 PropertyInfo property = null;
                 foreach (var p in type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public))
                 foreach (var p in type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public))
                 {
                 {
-                    if (EqualsIgnoreCasing(p.Name, propertyName))
+                    // only if it's not an indexer, we can do case-ignoring matches
+                    var isStandardIndexer = p.GetIndexParameters().Length == 1 && p.Name == "Item";
+                    if (!isStandardIndexer && EqualsIgnoreCasing(p.Name, propertyName))
                     {
                     {
                         property = p;
                         property = p;
                         break;
                         break;