Basic optional parameters support in binder. Fixes #13817
authorMarek Safar <marek.safar@gmail.com>
Thu, 8 Aug 2013 11:30:19 +0000 (13:30 +0200)
committerMarek Safar <marek.safar@gmail.com>
Thu, 8 Aug 2013 11:31:08 +0000 (13:31 +0200)
mcs/class/corlib/System.Reflection/Binder.cs
mcs/class/corlib/Test/System.Reflection/BinderTests.cs

index 5bdc14633c0cd1faeec5afc7dfa089ac1f66885f..7c0f829a38009aeef38578e6b3fda3755c6f2bf0 100644 (file)
@@ -32,6 +32,7 @@
 
 using System.Globalization;
 using System.Runtime.InteropServices;
+using System.Collections.Generic;
 
 namespace System.Reflection
 {
@@ -400,12 +401,12 @@ namespace System.Reflection
                                                if (i < names.Length)
                                                        continue;
 
-                                               selected = SelectMethod (bindingAttr, new MethodBase [] { m }, newTypes, newModifiers, true, args);
+                                               selected = SelectMethod (bindingAttr, new MethodBase [] { m }, newTypes, newModifiers, true, ref args);
                                                if (selected != null)
                                                        break;
                                        }
                                } else {
-                                       selected = SelectMethod (bindingAttr, match, types, modifiers, true, args);
+                                       selected = SelectMethod (bindingAttr, match, types, modifiers, true, ref args);
                                }
 
                                state = null;
@@ -618,11 +619,11 @@ namespace System.Reflection
 
                        public override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase [] match, Type [] types, ParameterModifier [] modifiers)
                        {
-                               return SelectMethod (bindingAttr, match, types, modifiers,
-                                       false, null);
+                               object[] args = null;
+                               return SelectMethod (bindingAttr, match, types, modifiers, false, ref args);
                        }
 
-                       MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers, bool allowByRefMatch, object[] arguments)
+                       MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers, bool allowByRefMatch, ref object[] arguments)
                        {
                                MethodBase m;
                                int i, j;
@@ -685,22 +686,57 @@ namespace System.Reflection
                                        return null;
 
                                MethodBase result = null;
+                               ParameterInfo[] result_pi = null;
                                for (i = 0; i < match.Length; ++i) {
                                        m = match [i];
-                                       ParameterInfo[] args = m.GetParametersInternal ();
-                                       if (args.Length != types.Length)
-                                               continue;
-                                       if (!check_arguments (types, args, allowByRefMatch))
+                                       var pi = m.GetParametersInternal ();
+                                       var full_pi = pi;
+                                       if (pi.Length != types.Length) {
+                                               if ((bindingAttr & BindingFlags.OptionalParamBinding) == 0)
+                                                       continue;
+
+                                               List<ParameterInfo> pi_reduced = null;
+                                               for (var ii = pi.Length - 1; ii >= 0; --ii) {
+                                                       if ((pi [ii].Attributes & ParameterAttributes.HasDefault) == 0)
+                                                               break;
+
+                                                       if (pi_reduced == null) {
+                                                               pi_reduced = new List<ParameterInfo> (pi);
+                                                       }
+
+                                                       pi_reduced.RemoveAt (ii);
+                                               }
+
+                                               if (pi_reduced == null || pi_reduced.Count != types.Length)
+                                                       continue;
+
+                                               pi = pi_reduced.ToArray ();
+                                       }
+
+                                       if (!check_arguments (types, pi, allowByRefMatch))
                                                continue;
 
-                                       if (result != null)
+                                       if (result != null) {
                                                result = GetBetterMethod (result, m, types);
-                                       else
-                                               result = m;
+                                               if (result != m)
+                                                       continue;
+                                       }
+
+                                       result = m;
+                                       result_pi = full_pi;
                                }
 
-                               if (result != null || arguments == null || types.Length != arguments.Length)
+                               if (result != null) {
+                                       i = arguments == null ? 0 : arguments.Length;
+                                       Array.Resize (ref arguments, result_pi.Length);
+                                       for (; i < arguments.Length; ++i)
+                                               arguments [i] = result_pi [i].DefaultValue;
+
                                        return result;
+                               }
+
+                               if (arguments == null || types.Length != arguments.Length)
+                                       return null;
 
                                // Xamarin-5278: try with parameters that are COM objects
                                // REVIEW: do we also need to implement best method match?
index 08235e8cec6c5f52e4df234210a334767fdb61f3..ab0c5356aff0c33c7b5731492387a3a638c2d4ae 100644 (file)
@@ -174,6 +174,14 @@ namespace MonoTests.System.Reflection
                }
        }
 
+       class DefaultValues
+       {
+               public int Value;
+               public DefaultValues (int i = 5)
+               {
+                       Value = i;
+               }
+       }
 
        [TestFixture]
        public class BinderTest
@@ -187,6 +195,16 @@ namespace MonoTests.System.Reflection
                        var o = Activator.CreateInstance (typeof (ParamsArrayTest), new object[] { test_args });
                        Assert.IsNotNull (o, "#A1");
                }
+
+               [Test]
+               public void DefaultParameter ()
+               {
+                       var o = Activator.CreateInstance (typeof (DefaultValues),
+                               BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance | BindingFlags.OptionalParamBinding,
+                               null, null, null);
+                       var a = o as DefaultValues;
+                       Assert.AreEqual (5, a.Value);
+               }
                
                [Test]
                [ExpectedException (typeof (ArgumentException))]