2 // System.Reflection.BinderTests - Tests Type.DefaultBinder
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (c) 2004 Novell, Inc. (http://www.novell.com)
10 using NUnit.Framework;
12 using System.Globalization;
14 using System.Reflection;
16 namespace MonoTests.System.Reflection
25 public static void SampleMethod (object o) { }
27 public Type this[decimal i] {
28 get { return i.GetType (); }
31 public Type this[object i] {
32 get { return i.GetType (); }
38 public Type this [int i] {
39 get { return i.GetType (); }
45 public Type this[byte i] {
46 get { return i.GetType (); }
49 public Type this[sbyte i] {
50 get { return i.GetType (); }
53 public Type this[short i] {
54 get { return i.GetType (); }
57 public Type this[ushort i] {
58 get { return i.GetType (); }
61 public Type this[int i] {
62 get { return i.GetType (); }
65 public Type this[uint i] {
66 get { return i.GetType (); }
69 public Type this[long i] {
70 get { return i.GetType (); }
73 public Type this[ulong i] {
74 get { return i.GetType (); }
77 public Type this[float i] {
78 get { return i.GetType (); }
81 public Type this[double i] {
82 get { return i.GetType (); }
85 public Type this[decimal i] {
86 get { return i.GetType (); }
89 public Type this[object i] {
90 get { return i.GetType (); }
93 public Type this[Enum i] {
94 get { return i.GetType (); }
99 public class BinderTest
101 Binder binder = Type.DefaultBinder;
104 [ExpectedException (typeof (ArgumentException))]
105 public void SelectPropertyTestNull1 ()
107 // The second argument is the one
108 binder.SelectProperty (0, null, null, null, null);
112 [ExpectedException (typeof (ArgumentException))]
113 public void SelectPropertyTestEmpty ()
115 // The second argument is the one
116 binder.SelectProperty (0, new PropertyInfo [] {}, null, null, null);
120 [ExpectedException (typeof (AmbiguousMatchException))]
121 public void AmbiguousProperty1 () // Bug 58381
123 Type type = typeof (MultiIndexer);
124 PropertyInfo pi = type.GetProperty ("Item");
128 public void SelectAndInvokeAllProperties1 ()
130 Type type = typeof (MultiIndexer);
131 PropertyInfo [] props = type.GetProperties (BindingFlags.DeclaredOnly |
132 BindingFlags.Public |
133 BindingFlags.Instance);
135 // These don't cause an AmbiguousMatchException
136 Type [] types = { typeof (byte), typeof (short),
137 typeof (int), typeof (long),
140 /* MS matches short for sbyte!!! */
141 /* MS matches int for ushort!!! */
142 /* MS matches long for uint!!! */
143 /** These do weird things under MS if used together and then in separate arrays *
144 Type [] types = { typeof (ulong), typeof (float), typeof (double),
145 typeof (decimal), typeof (object) };
148 MultiIndexer obj = new MultiIndexer ();
150 foreach (Type t in types) {
151 PropertyInfo prop = null;
153 prop = binder.SelectProperty (0, props, null, new Type [] {t}, null);
154 } catch (Exception e) {
155 throw new Exception ("Type: " + t, e);
157 Type gotten = (Type) prop.GetValue (obj, new object [] {Activator.CreateInstance (t)});
158 Assert.AreEqual (t, gotten);
163 public void SelectAndInvokeAllProperties2 ()
165 Type type = typeof (MultiIndexer);
166 PropertyInfo [] props = type.GetProperties (BindingFlags.DeclaredOnly |
167 BindingFlags.Public |
168 BindingFlags.Instance);
170 Type [] types = { typeof (ushort), typeof (char) };
172 MultiIndexer obj = new MultiIndexer ();
173 PropertyInfo prop1 = binder.SelectProperty (0, props, null, new Type [] {types [0]}, null);
174 PropertyInfo prop2 = binder.SelectProperty (0, props, null, new Type [] {types [1]}, null);
175 Assert.AreEqual (prop1, prop2);
179 public void Select1Match2 ()
181 Type type = typeof (SingleIndexer);
182 PropertyInfo [] props = type.GetProperties (BindingFlags.DeclaredOnly |
183 BindingFlags.Public |
184 BindingFlags.Instance);
185 PropertyInfo prop = binder.SelectProperty (0, props, null, new Type [0], null);
186 Assert.IsNull (prop, "empty");
190 public void Select1Match ()
192 Type type = typeof (SingleIndexer);
193 PropertyInfo [] props = type.GetProperties (BindingFlags.DeclaredOnly |
194 BindingFlags.Public |
195 BindingFlags.Instance);
199 prop = binder.SelectProperty (0, props, null, new Type [] { typeof (long) }, null);
200 Assert.IsNull (prop, "long");
201 prop = binder.SelectProperty (0, props, null, new Type [] { typeof (int) }, null);
202 Assert.IsNotNull (prop, "int");
203 prop = binder.SelectProperty (0, props, null, new Type [] { typeof (short) }, null);
204 Assert.IsNotNull (prop, "short");
208 public void SelectMethod_ByRef ()
210 Type type = typeof (ByRefMatch);
211 BindingFlags flags = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance;
216 MethodInfo mi_run = type.GetMethod ("Run", flags, binder,
217 new Type [] { typeof (int) }, null);
218 Assert.IsFalse (mi_run.GetParameters () [0].ParameterType.IsByRef, "#A1");
219 MethodInfo mi_run_ref = type.GetMethod ("Run", flags, binder,
220 new Type [] { typeof (int).MakeByRefType () }, null);
221 Assert.IsTrue (mi_run_ref.GetParameters () [0].ParameterType.IsByRef, "#A2");
223 match = new MethodBase [] { mi_run_ref };
224 types = new Type [] { typeof (int) };
225 selected = binder.SelectMethod (flags, match, types, null);
226 Assert.IsNull (selected, "#B1");
227 types = new Type [] { typeof (int).MakeByRefType () };
228 selected = binder.SelectMethod (flags, match, types, null);
229 Assert.AreSame (mi_run_ref, selected, "#B2");
231 match = new MethodBase [] { mi_run };
232 types = new Type [] { typeof (int) };
233 selected = binder.SelectMethod (flags, match, types, null);
234 Assert.AreSame (mi_run, selected, "#C1");
235 types = new Type [] { typeof (int).MakeByRefType () };
236 selected = binder.SelectMethod (flags, match, types, null);
237 Assert.IsNull (selected, "#C1");
239 match = new MethodBase [] { mi_run, mi_run_ref };
240 types = new Type [] { typeof (int) };
241 selected = binder.SelectMethod (flags, match, types, null);
242 Assert.AreSame (mi_run, selected, "#D1");
243 types = new Type [] { typeof (int).MakeByRefType () };
244 selected = binder.SelectMethod (flags, match, types, null);
245 Assert.AreSame (mi_run_ref, selected, "#D2");
249 public void ArgNullOnMethod () // see bug 58846. We throwed nullref here.
251 Type type = typeof (SampleClass);
252 BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod;
253 type.InvokeMember ("SampleMethod", flags, null, null, new object[] { null });
257 public void ArgNullOnProperty ()
259 Type type = typeof (SampleClass);
260 PropertyInfo [] props = type.GetProperties (BindingFlags.DeclaredOnly |
261 BindingFlags.Public |
262 BindingFlags.Instance);
264 PropertyInfo prop = binder.SelectProperty (0, props, null, new Type [] {null}, null);
265 Assert.IsNotNull (prop);
269 public void BindToMethod_ByRef ()
271 Type type = typeof (ByRefMatch);
272 BindingFlags flags = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance;
274 object [] args = new object [] { 5 };
277 CultureInfo culture = CultureInfo.InvariantCulture;
279 MethodInfo mi_run = type.GetMethod ("Run", flags, binder,
280 new Type [] { typeof (int) }, null);
281 Assert.IsFalse (mi_run.GetParameters () [0].ParameterType.IsByRef, "#A1");
282 MethodInfo mi_run_ref = type.GetMethod ("Run", flags, binder,
283 new Type [] { typeof (int).MakeByRefType () }, null);
284 Assert.IsTrue (mi_run_ref.GetParameters () [0].ParameterType.IsByRef, "#A2");
286 match = new MethodBase [] { mi_run };
287 selected = binder.BindToMethod (flags, match, ref args, null, culture,
289 Assert.AreSame (mi_run, selected, "#1");
291 match = new MethodBase [] { mi_run_ref };
292 selected = binder.BindToMethod (flags, match, ref args, null, culture,
294 Assert.AreSame (mi_run_ref, selected, "#2");
296 match = new MethodBase [] { mi_run, mi_run_ref };
297 selected = binder.BindToMethod (flags, match, ref args, null, culture,
299 Assert.AreSame (mi_run, selected, "#3");
301 match = new MethodBase [] { mi_run_ref, mi_run };
302 selected = binder.BindToMethod (flags, match, ref args, null, culture,
304 Assert.AreSame (mi_run, selected, "#4");
308 public void BindToMethodNamedArgs ()
310 Type t = typeof (Bug41691);
312 StringWriter sw = new StringWriter ();
315 object[] argValues = new object [] {"Hello", "World", "Extra", sw};
316 string [] argNames = new string [] {"firstName", "lastName"};
318 t.InvokeMember ("PrintName",
319 BindingFlags.InvokeMethod,
327 Assert.AreEqual ("Hello\nExtra\nWorld\n", sw.ToString ());
330 public class Bug41691
332 public static void PrintName (string lastName, string firstName, string extra, TextWriter output)
334 output.WriteLine (firstName);
335 output.WriteLine (extra);
336 output.WriteLine (lastName);
341 public void GetMethodAmbiguity ()
343 object IntegerObject = 5;
344 object IntArrayObject = new int[] {5, 2, 5};
345 object StringArrayObject = new string [] {"One", "Two"};
346 object [] IntParam = new object [] {IntegerObject};
347 object [] IntArrayParam = new object [] {IntArrayObject};
348 object [] StringArrayParam = new object [] {StringArrayObject};
351 Type betype = this.GetType ();
353 string name1 = "Bug42457Method";
354 string name2 = "Bug42457Method2";
356 MethodInfo mi_obj = betype.GetMethod (name1, Type.GetTypeArray (IntParam));
357 mi_obj.Invoke (be, IntParam);
358 Assert.AreEqual (1, bug42457, "#1");
359 MethodInfo mi_arr = betype.GetMethod (name1, Type.GetTypeArray (IntArrayParam));
360 mi_arr.Invoke (be, IntArrayParam);
361 Assert.AreEqual (2, bug42457, "#2");
362 MethodInfo mi_str = betype.GetMethod (name1, Type.GetTypeArray (StringArrayParam));
363 mi_str.Invoke (be, StringArrayParam);
364 Assert.AreEqual (3, bug42457, "#3");
366 MethodInfo m2_obj = betype.GetMethod (name2, Type.GetTypeArray (IntParam));
367 m2_obj.Invoke (be, IntParam);
368 Assert.AreEqual (1, bug42457_2, "#4");
369 MethodInfo m2_arr = betype.GetMethod (name2, Type.GetTypeArray (IntArrayParam));
370 m2_arr.Invoke (be, IntArrayParam);
371 Assert.AreEqual (2, bug42457_2, "#5");
372 MethodInfo m2_str = betype.GetMethod (name2, Type.GetTypeArray(StringArrayParam));
373 m2_str.Invoke (be, StringArrayParam);
374 Assert.AreEqual (3, bug42457_2, "#6");
379 public void NullableArg () {
380 MethodInfo method = (typeof (BinderTest)).GetMethod("SetA", new [] {typeof (Int32)});
381 Assert.AreEqual (5, method.Invoke (new BinderTest (), new object [] { 5 }));
384 public int SetA(Int32? a) {
389 static void MethodWithLongParam(long param)
394 public void TestParamsAttribute ()
396 MethodInfo mi = typeof (BinderTest).GetMethod ("params_method1", BindingFlags.Static|BindingFlags.Public, null, new Type [] { typeof (object), typeof (object) }, null);
397 Assert.AreEqual (typeof (object), mi.GetParameters ()[1].ParameterType);
399 MethodInfo mi2 = typeof (BinderTest).GetMethod ("params_method1", BindingFlags.Static|BindingFlags.Public, null, new Type [] { typeof (object), typeof (object), typeof (object) }, null);
400 Assert.AreEqual (typeof (object[]), mi2.GetParameters ()[1].ParameterType);
403 public static void params_method1 (object o, params object[] o2) {
406 public static void params_method1 (object o, object o2) {
409 public static double DoubleMethod (double d) {
413 public static float FloatMethod (float f) {
418 public void ChangeType ()
421 Assert.AreEqual (42.0, typeof (BinderTest).GetMethod ("DoubleMethod").Invoke (null, new object[] { (char)42 }));
424 Assert.AreEqual (42.0f, typeof (BinderTest).GetMethod ("FloatMethod").Invoke (null, new object[] { (char)42 }));
428 public void TestExactBinding ()
430 Type[] types = new Type[] { typeof(int) };
431 Assert.AreEqual (null, typeof (BinderTest).GetMethod("MethodWithLongParam", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.ExactBinding, null, types, null));
434 public void Bug42457Method (object thing)
439 public void Bug42457Method (Array thing)
444 public void Bug42457Method (string [] thing)
449 public void Bug42457Method2 (object thing)
454 public void Bug42457Method2 (Array thing)
459 public void Bug42457Method2 (string [] thing)
464 int bug42457, bug42457_2;
467 public void GetMethodAvoidAmbiguity2 ()
469 Type tType = this.GetType ();
470 Bug77079A a = new Bug77079C ();
472 tType.InvokeMember ("Bug77079",
473 BindingFlags.Public | BindingFlags.InvokeMethod |
474 BindingFlags.Instance,
475 null, this, new object[] {a});
476 Assert.AreEqual (2, bug77079);
481 public void Bug77079 (Bug77079A a)
486 public void Bug77079 (Bug77079B a)
491 public class Bug77079A
495 public class Bug77079B : Bug77079A
499 public class Bug77079C : Bug77079B
504 public void GetMethodAvoidAmbiguity3 ()
506 Type[] types = new Type[] { typeof (Bug76083ArgDerived) };
507 MethodInfo m = typeof (Bug76083Derived).GetMethod ("Foo", types);
508 Assert.AreEqual (typeof (Bug76083Derived), m.DeclaringType);
511 public class Bug76083ArgBase {}
512 public class Bug76083ArgDerived : Bug76083ArgBase {}
514 public class Bug76083Base
516 public void Foo (Bug76083ArgBase a) {}
519 public class Bug76083Derived : Bug76083Base
521 public new void Foo (Bug76083ArgBase a) {}
524 private const BindingFlags BUG324998_BINDING_FLAGS
525 = BindingFlags.Public | BindingFlags.NonPublic
526 | BindingFlags.Instance | BindingFlags.Static
527 | BindingFlags.IgnoreCase;
529 class Bug324998AGood { public virtual void f(int i1, int i2, bool b) {} }
531 class Bug324998BGood : Bug324998AGood { public override void f(int i1, int i2, bool b) {} }
533 class Bug324998ABad {
534 public virtual void f(int i1, int i2) {}
535 public virtual void f(int i1, int i2, bool b) {}
538 class Bug324998BBad : Bug324998ABad { public override void f(int i1, int i2, bool b) {} }
541 public void Bug324998Good () {
542 if (typeof(Bug324998BGood).GetMethod("f", BUG324998_BINDING_FLAGS) == null)
543 throw new Exception("Bug324998Good");
547 [ExpectedException (typeof (AmbiguousMatchException))]
548 public void Bug324998Bad () {
549 typeof(Bug324998BBad).GetMethod("f", BUG324998_BINDING_FLAGS);
552 void Bug380361 (MyEnum e) { }
555 public void TestEnumConversion ()
557 Type type = this.GetType ();
558 MethodInfo mi = type.GetMethod ("Bug380361", BindingFlags.NonPublic | BindingFlags.Instance, binder, new Type [] { typeof (MyEnum) }, null);
559 mi.Invoke (this, new object [] { (int)MyEnum.Zero });
563 [ExpectedException(typeof (ArgumentException))]
564 public void TestEnumConversion2 ()
566 Type type = this.GetType ();
567 MethodInfo mi = type.GetMethod ("Bug380361", BindingFlags.NonPublic | BindingFlags.Instance, binder, new Type [] { typeof (MyEnum) }, null);
568 mi.Invoke (this, new object [] { (long)MyEnum.Zero });
571 class AssertingBinder : Binder {
573 public static readonly AssertingBinder Instance = new AssertingBinder ();
575 public override FieldInfo BindToField (BindingFlags bindingAttr, FieldInfo [] match, object value, CultureInfo culture)
577 Assert.IsNotNull (match);
579 return Type.DefaultBinder.BindToField (bindingAttr, match, value, culture);
582 public override MethodBase BindToMethod (BindingFlags bindingAttr, MethodBase [] match, ref object [] args, ParameterModifier [] modifiers, CultureInfo culture, string [] names, out object state)
584 Assert.IsNotNull (match);
585 Assert.IsNotNull (args);
587 return Type.DefaultBinder.BindToMethod (bindingAttr, match, ref args, modifiers, culture, names, out state);
590 public override object ChangeType (object value, Type type, CultureInfo culture)
592 Assert.IsNotNull (value);
593 Assert.IsNotNull (type);
595 return Type.DefaultBinder.ChangeType (value, type, culture);
598 public override void ReorderArgumentArray (ref object [] args, object state)
600 Assert.IsNotNull (args);
602 Type.DefaultBinder.ReorderArgumentArray (ref args, state);
605 public override MethodBase SelectMethod (BindingFlags bindingAttr, MethodBase [] match, Type [] types, ParameterModifier [] modifiers)
607 Assert.IsNotNull (match);
608 Assert.IsNotNull (types);
610 return Type.DefaultBinder.SelectMethod (bindingAttr, match, types, modifiers);
613 public override PropertyInfo SelectProperty (BindingFlags bindingAttr, PropertyInfo [] match, Type returnType, Type [] indexes, ParameterModifier [] modifiers)
615 Assert.IsNotNull (match);
617 return Type.DefaultBinder.SelectProperty (bindingAttr, match, returnType, indexes, modifiers);
626 public int Add(int x, int y)
632 class Foo : BaseFoo {
636 public new void Bar ()
643 public void Run (int i)
647 public void Run (out int i)
653 [Test] // bug #471257
654 public void TestCustomBinderNonNullArgs ()
656 var foo = new Foo ();
658 typeof (Foo).InvokeMember (
660 BindingFlags.InvokeMethod,
661 AssertingBinder.Instance,
665 Assert.IsTrue (foo.Barred);
668 class Int32Binder : AssertingBinder
670 public override object ChangeType(Object value, Type type, CultureInfo ci)
672 if (value.GetType() == type) {
674 } else if (type.IsPrimitive) {
675 if (type == typeof(Int32))
676 return Convert.ToInt32(value);
678 throw new ArgumentException("missing support for primitive: " + type);
681 throw new ArgumentException("Could not ChangeType to " + type.FullName);
686 [ExpectedException(typeof (TargetParameterCountException))]
687 public void TestTargetParameterCountExceptionA ()
689 MethodInfo method = typeof (Foo).GetMethod ("Add");
690 method.Invoke((new Foo ()), 0, null, null, null);
694 [ExpectedException(typeof (TargetParameterCountException))]
695 public void TestTargetParameterCountExceptionB ()
697 MethodInfo method = typeof (Foo).GetMethod ("Add");
698 method.Invoke(new Foo (), 0, null, new object [] {1}, null);
702 public void TestBindingFlagsA ()
704 MethodInfo method = typeof (Foo).GetMethod ("Add");
705 method.Invoke((new Foo ()), 0, null, new object [] {1, 2}, null);
709 [ExpectedException(typeof (ArgumentException))]
710 public void TestBindingFlagsB ()
712 MethodInfo method = typeof (Foo).GetMethod ("Add");
713 method.Invoke((new Foo ()), 0, null, new object [] {1, "2"}, null);
717 public void TestBindingFlagsExactBindingA ()
719 MethodInfo method = typeof (Foo).GetMethod ("Add");
720 method.Invoke((new Foo ()), BindingFlags.ExactBinding, null, new object [] {1, 2}, null);
724 [ExpectedException(typeof (ArgumentException))]
725 public void TestBindingFlagsExactBindingB ()
727 MethodInfo method = typeof (Foo).GetMethod ("Add");
728 method.Invoke((new Foo ()), BindingFlags.ExactBinding, new Int32Binder (), new object [] {1, "2"}, null);
732 public void TestBindingFlagsExactBindingC ()
734 MethodInfo method = typeof (Foo).GetMethod ("Add");
735 method.Invoke((new Foo ()), 0, new Int32Binder (), new object [] {1, "2"}, null);