[Mono-list] Bug fix - 41691
B Anirban
banirban@novell.com
Mon, 08 Dec 2003 21:30:28 -0700
Hi,
I am posting here my fixes for bug 41691.
For this I felt a need for changing the check_type method (in
Binder.cs) for extracting better match. Hence I created here a
overloaded version of check_type method.
Also I overloaded the SelectMethod function for handling named
arguments.
I am attaching the test cases for the same as well.
Looking forward for your suggestion on this implementation.
Regards.
Anirban.
===================================================================
RCS file: /mono/mcs/class/corlib/System/MonoType.cs,v
retrieving revision 1.49
diff -u -r1.49 MonoType.cs
--- class/corlib/System/MonoType.cs 1 Aug 2003 14:59:42
-0000 1.49
+++ class/corlib/System/MonoType.cs 28 Nov 2003 21:02:17 -0000
@@ -299,7 +299,7 @@
if ((invokeAttr & BindingFlags.SetField) != 0 &&
((args == null) || args.Length != 1))
throw new ArgumentException
("invokeAttr");
if ((namedParameters != null) && ((args == null)
|| args.Length < namedParameters.Length))
- throw new ArgumentException
("namedParameters");
+ throw new ArgumentException
("namedParameters cannot be more than named arguments in number");
/* set some defaults if none are provided :-(
*/
if ((invokeAttr &
(BindingFlags.Public|BindingFlags.NonPublic)) == 0)
Index: class/corlib/System/TypeCode.cs
===================================================================
RCS file: /mono/mcs/class/corlib/System.Reflection/Binder.cs,v
retrieving revision 1.11
diff -u -r1.11 Binder.cs
--- class/corlib/System.Reflection/Binder.cs 11 May 2003 05:51:07
-0000 1.11
+++ class/corlib/System.Reflection/Binder.cs 28 Nov 2003 21:02:19
-0000
@@ -83,8 +83,14 @@
types [i] = args
[i].GetType ();
}
}
- MethodBase selected = SelectMethod
(bindingAttr, match, types, modifiers);
+
state = null;
+ MethodBase selected = null;
+ if(names == null)
+ selected = SelectMethod
(bindingAttr, match, types, modifiers);
+ else
+ selected = SelectMethod
(bindingAttr, match, ref args, modifiers, names);
+
return selected;
}
@@ -221,7 +234,214 @@
return to.IsAssignableFrom
(from);
}
}
+
+ private static bool check_type (Type from, Type
to, out int matchVal) {
+ if (from == to){
+ matchVal = 1;
+ return true;
+ }
+ TypeCode fromt = Type.GetTypeCode
(from);
+ TypeCode tot = Type.GetTypeCode (to);
+ matchVal = -1;
+
+ switch (fromt) {
+ case TypeCode.Char:
+ switch (tot) {
+ case TypeCode.UInt16:
+ matchVal = 2;
+ return true;
+ case TypeCode.UInt32:
+ matchVal = 3;
+ return true;
+ case TypeCode.Int32:
+ matchVal = 4;
+ return true;
+ case TypeCode.UInt64:
+ matchVal = 5;
+ return true;
+ case TypeCode.Int64:
+ matchVal = 6;
+ return true;
+ case TypeCode.Single:
+ matchVal = 7;
+ return true;
+ case TypeCode.Double:
+ matchVal = 8;
+ return true;
+ }
+ matchVal = 50;
+ return to == typeof (object);
+ case TypeCode.Byte:
+ switch (tot) {
+ case TypeCode.Char:
+ matchVal = 2;
+ return true;
+ case TypeCode.UInt16:
+ matchVal = 3;
+ return true;
+ case TypeCode.Int16:
+ matchVal = 4;
+ return true;
+ case TypeCode.UInt32:
+ matchVal = 5;
+ return true;
+ case TypeCode.Int32:
+ matchVal = 6;
+ return true;
+ case TypeCode.UInt64:
+ matchVal = 7;
+ return true;
+ case TypeCode.Int64:
+ matchVal = 8;
+ return true;
+ case TypeCode.Single:
+ matchVal = 9;
+ return true;
+ case TypeCode.Double:
+ matchVal = 10;
+ return true;
+ }
+ matchVal = 50;
+ return to == typeof (object) ||
(from.IsEnum && to == typeof (Enum));
+ case TypeCode.SByte:
+ switch (tot) {
+ case TypeCode.Int16:
+ matchVal = 2;
+ return true;
+ case TypeCode.Int32:
+ matchVal = 3;
+ return true;
+ case TypeCode.Int64:
+ matchVal = 4;
+ return true;
+ case TypeCode.Single:
+ matchVal = 5;
+ return true;
+ case TypeCode.Double:
+ matchVal = 6;
+ return true;
+ }
+ matchVal = 50;
+ return to == typeof (object) ||
(from.IsEnum && to == typeof (Enum));
+ case TypeCode.UInt16:
+ switch (tot) {
+ case TypeCode.UInt32:
+ matchVal = 2;
+ return true;
+ case TypeCode.Int32:
+ matchVal = 3;
+ return true;
+ case TypeCode.UInt64:
+ matchVal = 4;
+ return true;
+ case TypeCode.Int64:
+ matchVal = 5;
+ return true;
+ case TypeCode.Single:
+ matchVal = 6;
+ return true;
+ case TypeCode.Double:
+ matchVal = 7;
+ return true;
+ }
+ matchVal = 50;
+ return to == typeof (object) ||
(from.IsEnum && to == typeof (Enum));
+ case TypeCode.Int16:
+ switch (tot) {
+ case TypeCode.Int32:
+ matchVal = 2;
+ return true;
+ case TypeCode.Int64:
+ matchVal = 3;
+ return true;
+ case TypeCode.Single:
+ matchVal = 4;
+ return true;
+ case TypeCode.Double:
+ matchVal = 5;
+ return true;
+ }
+ matchVal = 50;
+ return to == typeof (object) ||
(from.IsEnum && to == typeof (Enum));
+ case TypeCode.UInt32:
+ switch (tot) {
+ case TypeCode.UInt64:
+ matchVal = 2;
+ return true;
+ case TypeCode.Int64:
+ matchVal = 3;
+ return true;
+ case TypeCode.Single:
+ matchVal = 4;
+ return true;
+ case TypeCode.Double:
+ matchVal = 5;
+ return true;
+ }
+ matchVal = 50;
+ return to == typeof (object) ||
(from.IsEnum && to == typeof (Enum));
+ case TypeCode.Int32:
+ switch (tot) {
+ case TypeCode.Int64:
+ matchVal = 2;
+ return true;
+ case TypeCode.Single:
+ matchVal = 3;
+ return true;
+ case TypeCode.Double:
+ matchVal = 4;
+ return true;
+ }
+ matchVal = 50;
+ return to == typeof (object) ||
(from.IsEnum && to == typeof (Enum));
+ case TypeCode.UInt64:
+ switch (tot) {
+ case TypeCode.Int64:
+ matchVal = 2;
+ return true;
+ case TypeCode.Single:
+ matchVal = 3;
+ return true;
+ case TypeCode.Double:
+ matchVal = 4;
+ return true;
+ }
+ matchVal = 50;
+ return to == typeof (object) ||
(from.IsEnum && to == typeof (Enum));
+
+ case TypeCode.Int64:
+ switch (tot) {
+ case TypeCode.UInt64:
+ matchVal = 2;
+ return true;
+ case TypeCode.Single:
+ matchVal = 3;
+ return true;
+ case TypeCode.Double:
+ matchVal = 4;
+ return true;
+ }
+ matchVal = 50;
+ return to == typeof (object) ||
(from.IsEnum && to == typeof (Enum));
+ case TypeCode.Single:
+ if(tot == TypeCode.Double){
+ matchVal = 2;
+ return true;
+ }
+ matchVal = 50;
+ return to == typeof (object);
+ default:
+ /* TODO: handle valuetype ->
byref */
+ if (to == typeof (object) &&
from.IsValueType){
+ matchVal = 50;
+ return true;
+ }
+
+ matchVal = 100;
+ return to.IsAssignableFrom
(from);
+ }
+ }
private static bool check_arguments (Type[]
types, ParameterInfo[] args) {
for (int i = 0; i < types.Length; ++i)
{
if (!check_type (types [i], args
[i].ParameterType))
@@ -229,6 +449,189 @@
}
return true;
}
+
+
+ private MethodBase SelectMethod (BindingFlags
bindingAttr,
+ MethodBase[] match, ref object[] args,
ParameterModifier[] modifiers,
+ string[] names)
+ {
+ int found = 0;
+ MethodBase m = null;
+ MethodBase tempM = null;
+ int matchVal = 0, totalMatchVal = 0,
utotalMatchVal = 0;
+ int selectedMethod = -1;
+ int NamedParamBestMatch = -1;
+ int UnnamedParamBestMatch = -1;
+ int [] matchSeq = new int
[names.Length];
+ int [] bestMatchSeq = new int
[names.Length];
+ int uNameParamLen = args.Length -
names.Length;
+ int [] ubestMatchSeq = null;
+ int [] umatchSeq = null;
+ if(uNameParamLen > 0){
+ ubestMatchSeq = new int
[uNameParamLen];
+ umatchSeq = new int
[uNameParamLen];
+ }
+ ParameterInfo[] param = null;
+
+ // go thru all the methods
+ for (int mi = 0; mi < match.Length;
++mi) {
+ m = match [mi];
+ param = m.GetParameters ();
+ // match the number of
prameters
+ if (args.Length !=
param.Length)
+ continue;
+ // for named parameters the
matching
+ // param name is major criteria
+ // the name has to be matched
+ int j, k;
+ totalMatchVal = 0;
+ utotalMatchVal = 0;
+ found = 0;
+ for(j = 0; j<names.Length;
j++){
+ for(k = 0;
k<param.Length; k++){
+
if(param[k].Name == names[j])
+
break;
+ }
+ // if even one param
name doesn't match
+ // don't consider the
method
+ if(k >=
param.Length){
+ found = -1;
+ break;
+ }
+
+ // if all the names
matches
+ // start checking types
for named
+ // parameters
+ matchVal = 0;
+ if (check_type (args
[j].GetType (), param[k].ParameterType, out matchVal)){
+ matchSeq [j] =
matchVal;
+ totalMatchVal =
totalMatchVal + matchVal;
+ }
+ else{
+ found = -1;
+ break;
+ }
+ }
+
+ //if name or type desn't not
match pickup next method
+ if(found == -1)
+ continue;
+
+ // check if there are any
unnamed urguments
+ if(names.Length < args.Length){
+ ParameterInfo[] parms =
param;
+ int currentPos =
names.Length;
+ for(int i=0, l=0;
i<parms.Length; i++){
+ for(j = 0;
j<names.Length; j++){
+
if(parms[i].Name == names[j])
+
break;
+ }
+ // chech types
for unnamed params
+ if((j >=
names.Length) && (args.Length > currentPos)){
+
+ if(check_type
(args[currentPos].GetType(), parms[i].ParameterType, out matchVal)){
+ umatchSeq
[l++] = matchVal;
+
utotalMatchVal = utotalMatchVal + matchVal;
+
currentPos++;
+ }
+ else{
+ found
= -1;
+
break;
+ }
+ }
+ }
+
+ }
+ //if types not matched pickup
next method
+ if(found == -1)
+ continue;
+
+ // lower the value, better the
match
+ // hence we will keep only the
least totalMatchvalue
+ // the preference goes to named
params
+ // first the named prams gets
chance to get the
+ // better match then comes
unnamed params
+ if (NamedParamBestMatch >
totalMatchVal || NamedParamBestMatch == -1){
+ NamedParamBestMatch =
totalMatchVal;
+ UnnamedParamBestMatch =
utotalMatchVal;
+ for (int n = 0;
n<names.Length; n++)
+ bestMatchSeq [n]
= matchSeq [n];
+ if(uNameParamLen > 0){
+ for (int u = 0;
u<uNameParamLen; u++)
+ ubestMatchSeq
[u] = umatchSeq [u];
+ }
+ selectedMethod = mi;
+ }
+
+ // if two method returns the
same value for
+ // then match types of each
param
+ // if all the types matches
return a
+ // AmbiguousMatchException
+ else if (NamedParamBestMatch ==
totalMatchVal){
+ bool noMatch = false;
+ int n = 0;
+ if(uNameParamLen > 0) {
+ if(UnnamedParamBestMatch
== utotalMatchVal){
+ for(n =
0; n<uNameParamLen; n++){
+ if(ubestMatchSeq
[n] != umatchSeq [n]){
+ noMatch
= true;
+ break;
+ }
+ }
+ }
+ else
+ noMatch
= true;
+ }
+ if(!noMatch){
+ for(n = 0;
n<names.Length; n++){
+ if(bestMatchSeq
[n] != matchSeq [n]){
+ noMatch
= true;
+ break;
+ }
+ }
+ }
+ if(!noMatch)
+ throw new
AmbiguousMatchException();
+
+ if((uNameParamLen>0) &&
(UnnamedParamBestMatch > utotalMatchVal)){
+ UnnamedParamBestMatch
= utotalMatchVal;
+ for (n = 0;
n<names.Length; n++)
+ bestMatchSeq
[n] = matchSeq [n];
+ for (int u = 0;
u<uNameParamLen; u++)
+ ubestMatchSeq
[u] = umatchSeq [u];
+ selectedMethod =
mi;
+ }
+ }
+
+ }
+ // if no method matched
+ if(selectedMethod == -1)
+ return null;
+
+ param =
match[selectedMethod].GetParameters ();
+
+ // rearrange the argumets as per the
+ // parameters of the qualified method
+ object[] tempArgs = new
object[args.Length];
+ int curPos = names.Length;
+
+ for(int t = 0; t<param.Length; t++){
+ int j;
+ for(j = 0; j<names.Length;
j++){
+ if(param[t].Name ==
names[j]){
+ tempArgs[t] =
args[j];
+ break;
+ }
+ }
+ if((j >= names.Length) &&
(args.Length > curPos)){
+ tempArgs[t] =
args[curPos];
+ curPos++;
+ }
+ }
+ args = tempArgs;
+ return match[selectedMethod];
+ }
+
public override MethodBase SelectMethod
(BindingFlags bindingAttr, MethodBase[] match, Type[] types,
ParameterModifier[] modifiers)
{
Index: class/corlib/Test/System/TypeTest.cs
===================================================================
RCS file: /mono/mcs/class/corlib/Test/System/TypeTest.cs,v
retrieving revision 1.1
diff -u -r1.1 TypeTest.cs
--- class/corlib/Test/System/TypeTest.cs 13 Jul 2003 14:29:25
-0000 1.1
+++ class/corlib/Test/System/TypeTest.cs 29 Nov 2003 11:37:56
-0000
@@ -8,8 +8,10 @@
using NUnit.Framework;
using System;
+using System.Reflection;
using System.IO;
+
namespace MonoTests.System
{
class Super : ICloneable {
@@ -20,11 +22,15 @@
class Duper: Super {
}
+
enum TheEnum { A, B, C };
[TestFixture]
public class TypeTest : Assertion
{
+ public static object [] values;
+ public static string methodId;
+
[Test]
public void TestIsAssignableFrom () {
// Simple tests for inheritance
@@ -77,6 +83,279 @@
public void TestIsSubclassOf () {
Assert (typeof (ICloneable).IsSubclassOf (typeof
(object)));
}
+
+ private void invokeMember(object [] argValues, string []
argNames) {
+ try {
+ values = new object[argValues.Length];
+
+ Type t = typeof(TypeClass);
+ t.InvokeMember("checkMethod",
+ BindingFlags.InvokeMethod,
+ null,
+ null,
+ argValues,
+ null,
+ null,
+ argNames);
+ } catch (Exception e) {
+ throw (e);
+ }
+ }
+
+ [Test]
+ public void TestInvokeMember_Method () {
+ try{
+ object[] argValues = new object []
{"aaa", "bbb"};
+ string [] argNames = new string []
{"firstName", "lastName"};
+ invokeMember(argValues, argNames);
+
+ AssertEquals("#A1", methodId, "m1");
+ AssertEquals("#A1", argValues[0],
values[0]);
+ AssertEquals("#A1", argValues[1],
values[1]);
+ }catch (Exception e){
+ Fail ("Unexpected exception at #A1 " +
e);
+ }
+
+ try{
+ object[] argValues = new object []
{"bbb", "aaa"};
+ string [] argNames = new string []
{"lastName", "firstName"};
+ invokeMember(argValues, argNames);
+
+ AssertEquals("#A2", methodId, "m1");
+ AssertEquals("#A2", argValues[0],
values[1]);
+ AssertEquals("#A2", argValues[1],
values[0]);
+ }catch (Exception e){
+ Fail ("Unexpected exception at #A2 " +
e);
+ }
+
+ try{
+ object[] argValues = new object [] {12,
"bbb"};
+ string [] argNames = new string []
{"firstName", "lastName"};
+ invokeMember(argValues, argNames);
+ }catch (Exception e){
+ AssertEquals("#A3",
typeof(AmbiguousMatchException), e.GetType());
+ }
+
+ try{
+ object[] argValues = new object []
{"aaa", 12};
+ string [] argNames = new string []
{"firstName", "lastName"};
+ invokeMember(argValues, argNames);
+ }catch (Exception e){
+ AssertEquals("#A4",
typeof(MissingMethodException), e.GetType());
+ }
+
+ try{
+ object[] argValues = new object []
{"aaa", 12};
+ string [] argNames = new string []
{"firstName",
+ "lastName",
"anotherName"};
+ invokeMember(argValues, argNames);
+ }catch (Exception e){
+ AssertEquals("#A5",
typeof(ArgumentException), e.GetType());
+ }
+
+ try{
+ double i = 10;
+ object[] argValues = new object []
{"aaa", "bbb", i};
+ string [] argNames = new string []
{"firstName",
+ "lastName",
"ID"};
+ invokeMember(argValues, argNames);
+
+ AssertEquals("#A6", methodId, "m4");
+ AssertEquals("#A6", argValues[0],
values[0]);
+ AssertEquals("#A6", argValues[1],
values[1]);
+ AssertEquals("#A6", argValues[2],
values[2]);
+ }catch (Exception e){
+ Fail ("Unexpected exception at #A6 " +
e);
+ }
+
+ try{
+ int i = 10;
+ object[] argValues = new object []
{"aaa", "bbb", i};
+ string [] argNames = new string []
{"firstName",
+ "lastName",
"ID"};
+ invokeMember(argValues, argNames);
+
+ AssertEquals("#A7", methodId, "m5");
+ AssertEquals("#A7", argValues[0],
values[0]);
+ AssertEquals("#A7", argValues[1],
values[1]);
+ AssertEquals("#A7", argValues[2],
values[2]);
+ }catch (Exception e){
+ Fail ("Unexpected exception at #A7 " +
e);
+ }
+
+ // unnamed parameters
+ try{
+ int i = 10;
+ object[] argValues = new object []
{"aaa", "bbb", i};
+ string [] argNames = new string []
{"firstName", "lastName"};
+ invokeMember(argValues, argNames);
+
+ AssertEquals("#A8", methodId, "m5");
+ AssertEquals("#A8", argValues[0],
values[0]);
+ AssertEquals("#A8", argValues[1],
values[1]);
+ AssertEquals("#A8", argValues[2],
values[2]);
+ }catch (Exception e){
+ Fail ("Unexpected exception at #A8 " +
e);
+ }
+
+ try{
+ Int16 i = 10;
+ object[] argValues = new object []
{"aaa", i, "zzz", 500};
+ string [] argNames = new string []
{"firstName", "ID"};
+ invokeMember(argValues, argNames);
+
+ AssertEquals("#A9", methodId, "m7");
+ AssertEquals("#A9", argValues[0],
values[0]);
+ AssertEquals("#A9", argValues[1],
values[1]);
+ AssertEquals("#A9", argValues[2],
values[2]);
+ AssertEquals("#A9", argValues[3],
values[3]);
+ }catch (Exception e){
+ Fail ("Unexpected exception at #A9 " +
e);
+ }
+
+ try{
+ short s = 500;
+ Int64 i = 10;
+ object[] argValues = new object []
{"aaa", i, "zzz", s};
+ string [] argNames = new string []
{"firstName", "ID"};
+ invokeMember(argValues, argNames);
+
+ AssertEquals("#A10", methodId, "m8");
+ AssertEquals("#A10", argValues[0],
values[0]);
+ AssertEquals("#A10", argValues[1],
values[1]);
+ AssertEquals("#A10", argValues[2],
values[2]);
+ AssertEquals("#A10", argValues[3],
values[3]);
+ }catch (Exception e){
+ Fail ("Unexpected exception at #A10 " +
e);
+ }
+
+ try{
+ Int16 i = 10;
+ Int16 s = 500;
+ object[] argValues = new object []
{"aaa", i, "zzz", s};
+ string [] argNames = new string []
{"firstName", "ID"};
+ invokeMember(argValues, argNames);
+
+ AssertEquals("#A11", methodId, "m7");
+ AssertEquals("#A11", argValues[0],
values[0]);
+ AssertEquals("#A11", argValues[1],
values[1]);
+ AssertEquals("#A11", argValues[2],
values[2]);
+ AssertEquals("#A11", argValues[3],
values[3]);
+ }catch (Exception e){
+ Fail ("Unexpected exception at #A11 " +
e);
+ }
+
+ try{
+ object[] argValues = new object []
{"aaa", 12, "bbb", "zzz", 20};
+ string [] argNames = new string []
{"firstName", "ID"};
+ invokeMember(argValues, argNames);
+ }catch (Exception e){
+ AssertEquals("#A12",
typeof(AmbiguousMatchException), e.GetType());
+ }
+
+ try{
+ object[] argValues = new object []
{"aaa", 12, "bbb", "zzz"};
+ string [] argNames = new string []
{"firstName", "ID"};
+ invokeMember(argValues, argNames);
+ }catch (Exception e){
+ AssertEquals("#A13",
typeof(MissingMethodException), e.GetType());
+ }
+
+
+ try{
+ object[] argValues = new object []
{"aaa", 12, 20, "bbb"};
+ string [] argNames = new string []
{"firstName", "ID"};
+ invokeMember(argValues, argNames);
+ }catch (Exception e){
+ AssertEquals("#A14",
typeof(MissingMethodException), e.GetType());
+ }
+ }
}
+
+ public class TypeClass
+ {
+ public static void checkMethod(string lastName, string
firstName)
+ {
+ TypeTest.methodId = "m1";
+ TypeTest.values[0] = firstName;
+ TypeTest.values[1] = lastName;
+ }
+
+ public static void checkMethod(string lastName, int
firstName)
+ {
+ TypeTest.methodId = "m2";
+ }
+
+ public static void checkMethod(int firstName, string
lastName)
+ {
+ TypeTest.methodId = "m3";
+ }
+
+ public static void checkMethod(string lastName, double
ID, string firstName)
+ {
+ TypeTest.methodId = "m4";
+ TypeTest.values[0] = firstName;
+ TypeTest.values[1] = lastName;
+ TypeTest.values[2] = ID;
+ }
+
+ public static void checkMethod(long ID, string lastName,
string firstName)
+ {
+ TypeTest.methodId = "m5";
+ TypeTest.values[0] = firstName;
+ TypeTest.values[1] = lastName;
+ TypeTest.values[2] = ID;
+ }
+
+ public static void checkMethod(Int64 ID, string
lastName, string firstName, Int64 sal)
+ {
+ TypeTest.methodId = "m6";
+ TypeTest.values[0] = firstName;
+ TypeTest.values[1] = ID;
+ TypeTest.values[2] = lastName;
+ TypeTest.values[3] = sal;
+ }
+
+ public static void checkMethod(Int32 ID, string
lastName, string firstName, int sal)
+ {
+ TypeTest.methodId = "m7";
+ TypeTest.values[0] = firstName;
+ TypeTest.values[1] = ID;
+ TypeTest.values[2] = lastName;
+ TypeTest.values[3] = sal;
+ }
+
+ public static void checkMethod(Int64 ID, string
lastName, Int32 sal, string firstName)
+ {
+ TypeTest.methodId = "m8";
+ TypeTest.values[0] = firstName;
+ TypeTest.values[1] = ID;
+ TypeTest.values[2] = lastName;
+ TypeTest.values[3] = sal;
+ }
+
+ public static void checkMethod(Int32 ID, string
lastName, string firstName, long sal)
+ {
+ TypeTest.methodId = "m9";
+ TypeTest.values[0] = firstName;
+ TypeTest.values[1] = ID;
+ TypeTest.values[2] = lastName;
+ TypeTest.values[3] = sal;
+ }
+
+
+ public static void checkMethod(Int32 ID, string val,
string lastName, string firstName, long sal)
+ {
+ TypeTest.methodId = "m9";
+ }
+
+ public static void checkMethod(Int32 ID, string val,
string lastName, long sal, string firstName)
+ {
+ TypeTest.methodId = "m9";
+ }
+
+
+ }
+
}