First, repeat after me… Reflection is good. Reflection is good. Reflection is good.
We can use System.Type.GetMethod to get access to a methods metadata and then use System.Reflection.MethodBase.Invoke to execute the method.
So, given a class FooMaster with a private, static method Foo
1 public class FooMaster
2 {
3 private static bool Foo(string myString, int myInt)
4 {
5 //init the result
6 bool result = false;
7
8 //does the length of string match the int passed in?
9 if (myString != null)
10 {
11 result = myString.Length == myInt;
12 }
13 else if (myInt == 0)
14 {
15 result = true;
16 }
17
18 return result;
19 }
20 }
a unit test would look something like this
1 [Test]
2 public void Foo1()
3 {4 System.Reflection.MethodInfo fooMethod =
5 typeof(FooMaster).GetMethod("Foo",
6 (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static));
7 8 object[] parameterValues = { "my test string", 14 };
9 10 bool result = (bool)fooMethod.Invoke(null, parameterValues);
11 12 Assert.IsTrue(result, "Foo did not return the expected result!");
13 }In this case, because FooMaster.Foo is a private, static method, we need to include the
System.Reflection.BindingFlags.NonPublicSystem.Reflection.BindingFlags.StaticThe array of System.Object
object[] parameterValues = { "my test string", 14 };
When executing with the Invoke method
bool result = (bool)fooMethod.Invoke(null, parameterValues);
¡Hay Chimba! Life is good...until an overload is introduced. Now we need to do a little bit more work.
Introducing an overload of Foo that looks like this
1 private static bool Foo(string myString, byte myByte)
2 {3 return Foo(myString, Convert.ToInt32(myByte));
4 }will cause our unit test to throw a System.Reflection.AmbiguousMatchException exception since FooMaster now has two methods named Foo.
So, we need to update our unit test a bit to include an array of Type objects that represent the number, order, and type of parameters for the method that we're trying to get a reference to.
1 [Test]
2 public void Foo1()
3 {4 System.Reflection.MethodInfo fooMethod =
5 typeof(FooMaster).GetMethod("Foo",
6 (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static),
7 null, new Type[] { typeof(string), typeof(int) }, null);
8 9 object[] parameterValues = { "my test string", 14 };
10 11 bool result = (bool)fooMethod.Invoke(null, parameterValues);
12 13 Assert.IsTrue(result, "Foo did not return the expected result!");
14 } 15 16 [Test]
17 public void Foo2()
18 {19 System.Reflection.MethodInfo fooMethod =
20 typeof(FooMaster).GetMethod("Foo",
21 (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static),
22 null, new Type[] { typeof(string), typeof(byte) }, null);
23 24 object[] parameterValues = { "my test string", (byte)14 };
25 26 bool result = (bool)fooMethod.Invoke(null, parameterValues);
27 28 Assert.IsTrue(result, "Foo did not return the expected result!");
29 }You can see here that our unit tests include an array of Type
new Type[] { typeof(string), typeof(int) }
new Type[] { typeof(string), typeof(byte) }
to futher specify which Foo method to get a reference to.
Very cool. Remember...Reflection is good.



0 comments:
Post a Comment