Просмотр исходного кода

Added full support for interop with methods that have default values (#597)

boennhoff 6 лет назад
Родитель
Сommit
c1f59091cc

+ 20 - 0
Jint.Tests/Runtime/Domain/A.cs

@@ -104,5 +104,25 @@ namespace Jint.Tests.Runtime.Domain
         {
             callback(18);
         }
+
+        public int Call19(int a = 0)
+        {
+            return a;
+        }
+
+        public static int Call19Static(int a = 0)
+        {
+            return a;
+        }
+
+        public int Call20(int a, int b = 1, int c = 2)
+        {
+            return a + b + c;
+        }
+
+        public static int Call20Static(int a, int b = 1, int c = 2)
+        {
+            return a + b + c;
+        }
     }
 }

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

@@ -7,6 +7,7 @@ using System.Reflection;
 using Jint.Native;
 using Jint.Native.Array;
 using Jint.Native.Object;
+using Jint.Runtime.Interop;
 using Jint.Tests.Runtime.Converters;
 using Jint.Tests.Runtime.Domain;
 using Shapes;
@@ -171,6 +172,28 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void DelegateWithDefaultValueParametersCanBeInvoked()
+        {
+            var instance = new A();
+            _engine.SetValue("Instance", instance);
+            _engine.SetValue("Class", TypeReference.CreateTypeReference(_engine, typeof(A)));
+
+            RunTest(@"
+                assert(Instance.Call19() === 0);
+                assert(Instance.Call19(1) === 1);
+                assert(Instance.Call20(1) === 4);
+                assert(Instance.Call20(1, 2) === 5);
+                assert(Instance.Call20(1 , 2, 3) === 6);
+
+                assert(Class.Call19Static() === 0);
+                assert(Class.Call19Static(1) === 1);
+                assert(Class.Call20Static(1) === 4);
+                assert(Class.Call20Static(1, 2) === 5);
+                assert(Class.Call20Static(1 , 2, 3) === 6);
+            ");
+        }
+
         [Fact]
         public void CanGetObjectProperties()
         {

+ 1 - 1
Jint/Runtime/Interop/MethodInfoFunctionInstance.cs

@@ -31,7 +31,7 @@ namespace Jint.Runtime.Interop
 
             var converter = Engine.ClrTypeConverter;
 
-            foreach (var tuple in TypeConverter.FindBestMatch(methodInfos, ArgumentProvider))
+            foreach (var tuple in TypeConverter.FindBestMatch(_engine, methodInfos, ArgumentProvider))
             {
                 var method = tuple.Item1;
                 var arguments = tuple.Item2;

+ 1 - 1
Jint/Runtime/Interop/TypeReference.cs

@@ -53,7 +53,7 @@ namespace Jint.Runtime.Interop
 
             var constructors = ReferenceType.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
 
-            foreach (var tuple in TypeConverter.FindBestMatch(constructors, (info, b) => arguments))
+            foreach (var tuple in TypeConverter.FindBestMatch(_engine, constructors, (info, b) => arguments))
             {
                 var method = tuple.Item1;
 

+ 26 - 1
Jint/Runtime/TypeConverter.cs

@@ -494,7 +494,7 @@ namespace Jint.Runtime
             }
         }
 
-        public static IEnumerable<Tuple<MethodBase, JsValue[]>> FindBestMatch<T>(T[] methods, Func<T, bool, JsValue[]> argumentProvider) where T : MethodBase
+        public static IEnumerable<Tuple<MethodBase, JsValue[]>> FindBestMatch<T>(Engine engine, T[] methods, Func<T, bool, JsValue[]> argumentProvider) where T : MethodBase
         {
             System.Collections.Generic.List<Tuple<T, JsValue[]>> matchingByParameterCount = null;
             foreach (var m in methods)
@@ -522,6 +522,31 @@ namespace Jint.Runtime
                     matchingByParameterCount = matchingByParameterCount ?? new System.Collections.Generic.List<Tuple<T, JsValue[]>>();
                     matchingByParameterCount.Add(new Tuple<T, JsValue[]>(m, arguments));
                 }
+                else if (parameterInfos.Length > arguments.Length)
+                {
+                    // check if we got enough default values to provide all parameters (or more in case some default values are provided/overwritten)
+                    var defaultValuesCount = 0;
+                    foreach (var param in parameterInfos)
+                    {
+                        if (param.HasDefaultValue) defaultValuesCount++;
+                    }
+
+                    if (parameterInfos.Length <= arguments.Length + defaultValuesCount)
+                    {
+                        // create missing arguments from default values
+
+                        var argsWithDefaults = new System.Collections.Generic.List<JsValue>(arguments);
+                        for (var i = arguments.Length; i < parameterInfos.Length; i++)
+                        {
+                            var param = parameterInfos[i];
+                            var value = JsValue.FromObject(engine, param.DefaultValue);
+                            argsWithDefaults.Add(value);
+                        }
+
+                        matchingByParameterCount = matchingByParameterCount ?? new System.Collections.Generic.List<Tuple<T, JsValue[]>>();
+                        matchingByParameterCount.Add(new Tuple<T, JsValue[]>(m, argsWithDefaults.ToArray()));
+                    }
+                }
             }
 
             if (matchingByParameterCount == null)