Dowemo
0 0 0 0


Question:

There are a group of private methods in my class, and I need to call one dynamically based on an input value. Both the invoking code and the target methods are in the same instance. The code looks like this:

MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType);
dynMethod.Invoke(this, new object[] { methodParams });

In this case, GetMethod() will not return private methods. What BindingFlags do I need to supply to GetMethod() so that it can locate private methods?


Best Answer:


Reflection especially on private members is wrong

  • Reflection breaks type safety. You can try to invoke a method that doesn't exists (anymore), or with the wrong parameters, or with too much parameters, or not enough... or even in the wrong order (this one my favourite :) ). By the way return type could change as well.
  • Reflection is slow.

Private members reflection breaks encapsulation principle and thus exposing your code to the following :

  • Increase complexity of your code because it has to handle the inner behavior of the classes. What is hidden should remain hidden.
  • Makes your code easy to break as it will compile but won't run if the method changed its name.
  • Makes the private code easy to break because if it is private it is not intended to be called that way. Maybe the private method expects some inner state before being called.

What if I must do it anyway ?

There are so cases, when you depend on a third party or you need some api not exposed, you have to do some reflection. Some also use it to test some classes they own but that they don't want to change the interface to give access to the inner members just for tests.

If you do it, do it right

  • Mitigate the easy to break:

To mitigate the easy to break issue, the best is to detect any potential break by testing in unit tests that would run in a continuous integration build or such. Of course, it means you always use the same assembly (which contains the private members). If you use a dynamic load and reflection, you like play with fire, but you can always catch the Exception that the call may produce.

  • Mitigate the slowness of reflection:

In the recent versions of .Net Framework, CreateDelegate beat by a factor 50 the MethodInfo invoke:

// The following should be done once since this does some reflection
var method = this.GetType().GetMethod("Draw_" + itemType, 
  BindingFlags.NonPublic | BindingFlags.Instance);
// Here we create a Func that targets the instance of type which has the 
// Draw_ItemType method
var draw = (Func<TInput, Output[]>)_method.CreateDelegate(
                 typeof(Func<TInput, TOutput[]>), this);

draw calls will be around 50x faster than MethodInfo.Invokeuse draw as a standard Func like that:

var res = draw(methodParams);

Check this post of mine to see benchmark on different method invocations




Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs