381

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?

Dariusz Woźniak
  • 9,640
  • 6
  • 60
  • 73
Jeromy Irvine
  • 11,614
  • 3
  • 39
  • 52

11 Answers11

587

Simply change your code to use the overloaded version of GetMethod that accepts BindingFlags:

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

Here's the BindingFlags enumeration documentation.

gunr2171
  • 16,104
  • 25
  • 61
  • 88
wprl
  • 24,489
  • 11
  • 55
  • 70
  • 300
    I am going to get myself into so much trouble with this. – Frank Schwieterman Mar 10 '09 at 18:10
  • 2
    `BindingFlags.NonPublic` not returning `private` method.. :( – Moumit Oct 22 '14 at 10:25
  • 6
    @MoumitMondal are your methods static? You have to specify `BindingFlags.Instance` as well as `BindingFlags.NonPublic` for non-static methods. – BrianS Nov 26 '14 at 16:06
  • No @BrianS .. the method is `non-static` and `private` and the class is inherited from `System.Web.UI.Page` .. it make me fool anyway .. i did not find the reason.. :( – Moumit Nov 27 '14 at 10:33
  • That's what I meant. A non-static, private method needs both binding flags. However, your issue would appear to be due to inheritance. Here's a relevant question: http://stackoverflow.com/q/12360985/264628 – BrianS Nov 28 '14 at 13:58
  • You might need BindingFlags.Static too if some methods are static – andrew pate Sep 07 '17 at 15:48
  • 4
    Adding `BindingFlags.FlattenHierarchy` will enable you to get methods from parent classes to your instance. – Dragonthoughts Aug 22 '18 at 09:29
  • But `MethodBase.Invoke` for non-public methods needs in some cases `ReflectionPermission`, as stated in MSDN. Althought it is usually true. – Кое Кто Oct 25 '18 at 16:12
  • 2
    The amount of likes on that first comment disturbs me. Yet, I am about to use this. The reason that I had to look it up is because I generally try to avoid this. This is typically bad, but there are some scenarios where it works. Which is why it's there, and why I'm here. Please don't abuse this. – Jesse May 13 '20 at 14:47
  • 1
    This will throw Ambiguous match if you have overloads. And you can't use the overload which specify parameter types as it only works on public methods. What you can do though, is calling GetMethods instead and match it manually. – jeromej Aug 04 '22 at 08:29
  • @FrankSchwieterman did you end up getting into troubles? – AvielNiego Oct 02 '22 at 23:15
75

BindingFlags.NonPublic will not return any results by itself. As it turns out, combining it with BindingFlags.Instance does the trick.

MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType, 
    BindingFlags.NonPublic | BindingFlags.Instance);
Jeromy Irvine
  • 11,614
  • 3
  • 39
  • 52
55

And if you really want to get yourself in trouble, make it easier to execute by writing an extension method:

static class AccessExtensions
{
    public static object call(this object o, string methodName, params object[] args)
    {
        var mi = o.GetType ().GetMethod (methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance );
        if (mi != null) {
            return mi.Invoke (o, args);
        }
        return null;
    }
}

And usage:

    class Counter
    {
        public int count { get; private set; }
        void incr(int value) { count += value; }
    }

    [Test]
    public void making_questionable_life_choices()
    {
        Counter c = new Counter ();
        c.call ("incr", 2);             // "incr" is private !
        c.call ("incr", 3);
        Assert.AreEqual (5, c.count);
    }
cod3monk3y
  • 9,508
  • 6
  • 39
  • 54
  • 15
    Dangerous? Yes. But a great helper extension when wrapped in my unit testing namespace. Thanks for this. – Robert Wahler Aug 29 '14 at 13:38
  • 5
    If you care about real exceptions thrown from the method called it is a good idea to wrap it into try catch block and re-throw inner exception instead when TargetInvokationException caught. I do that in my unit test helper extension. – Slobodan Savkovic Feb 24 '16 at 18:40
  • 3
    Reflection dangerous? Hmmm... C# , Java, Python... actually everything is dangerous, even the world :D You just have to take care about how to do it safely... – Legends Feb 01 '18 at 12:19
  • @Legends It *is* dangerous because private code usually changes a lot. You have no guarantee that the method even exists in the future. And you don't know how the method operates or how it cooperates with other methods. It may lead to unwanted side effects when you call a private method that was obviously not meant to serve as the entry point for a particular functionality. For example, the method could only work properly if the context is configured correctly by another method that is internally called before the method you are invoking. –  Aug 06 '23 at 20:11
  • @Legends Call it dangerous or stupid to call internal or private code. Because it is possible you shouldn't do it. At least if you value a robust code base for your application. –  Aug 06 '23 at 20:11
  • @RobertWahler Unit testing private methods... There is already enough said about this. Testing the public API naturally tests the private internals that serve the API. –  Aug 06 '23 at 20:12
27

Microsoft recently modified the reflection API rendering most of these answers obsolete. The following should work on modern platforms (including Xamarin.Forms and UWP):

obj.GetType().GetTypeInfo().GetDeclaredMethod("MethodName").Invoke(obj, yourArgsHere);

Or as an extension method:

public static object InvokeMethod<T>(this T obj, string methodName, params object[] args)
{
    var type = typeof(T);
    var method = type.GetTypeInfo().GetDeclaredMethod(methodName);
    return method.Invoke(obj, args);
}

Note:

  • If the desired method is in a superclass of obj the T generic must be explicitly set to the type of the superclass.

  • If the method is asynchronous you can use await (Task) obj.InvokeMethod(…).

Owen James
  • 628
  • 7
  • 16
  • It doesn't work for UWP .net version at least because it works only for ***public*** methods: "_Returns a collection that contains **all public methods** declared on the current type that match the specified name_". – Dmytro Bondarenko Feb 16 '17 at 23:26
  • 2
    @DmytroBondarenko I tested it against private methods and it worked. I did see that, however. Not sure why it behaves differently from the documentation, but at least it works. – Owen James Feb 16 '17 at 23:42
  • 1
    Yeah, I wouldn't call all other answers obsolete, if the documentation says `GetDeclareMethod()` is intended to be used to retrieve only a public method. – Mass Dot Net Aug 27 '19 at 12:20
14

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.Invoke use draw as a standard Func like that:

var res = draw(methodParams);

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

Community
  • 1
  • 1
Fab
  • 14,327
  • 5
  • 49
  • 68
  • 1
    Although I get dependency injection should be a prefered way of unit-testing, I guess used with caution is not totally evil to use reflection to access units that would otherwise be inaccessable for testing. Personally I think as well as the normal [public][protected][private] modifiers we should also have [Test][Composition] modifiers so it is possible to have certain things visible during these stages without being forced to make everything full public (and therefore have to fully document those methods) – andrew pate Sep 07 '17 at 10:08
  • 1
    Thanks Fab for listing the problems of reflecting on private members, it has caused me to review how I feel about using it and came a conclusion...Using reflection to unit-test your private members is wrong, however leaving code-paths untested is really really wrong. – andrew pate Sep 07 '17 at 15:46
  • 3
    But when it comes to unit testing of generally not-unit-testable legacy code, it is brilliant way to do it – T.S. May 23 '18 at 04:54
9

Are you absolutely sure this can't be done through inheritance? Reflection is the very last thing you should look at when solving a problem, it makes refactoring, understanding your code, and any automated analysis more difficult.

It looks like you should just have a DrawItem1, DrawItem2, etc class that override your dynMethod.

Bill K
  • 62,186
  • 18
  • 105
  • 157
  • 1
    @Bill K: Given other circumstances, we decided not to use inheritance for this, hence the use of reflection. For most cases, we would do it that way. – Jeromy Irvine Sep 25 '08 at 19:32
4

It should be noted that calling from a derived class can be problematic.

Error prone:

this.GetType().GetMethod("PrivateTestMethod", BindingFlags.Instance | BindingFlags.NonPublic)

Correct:

typeof(CurrentClass).GetMethod("PrivateTestMethod", BindingFlags.Instance | BindingFlags.NonPublic)
urglas
  • 41
  • 1
3

Invokes any method despite its protection level on object instance. Enjoy!

public static object InvokeMethod(object obj, string methodName, params object[] methodParams)
{
    var methodParamTypes = methodParams?.Select(p => p.GetType()).ToArray() ?? new Type[] { };
    var bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
    MethodInfo method = null;
    var type = obj.GetType();
    while (method == null && type != null)
    {
        method = type.GetMethod(methodName, bindingFlags, Type.DefaultBinder, methodParamTypes, null);
        type = type.BaseType;
    }

    return method?.Invoke(obj, methodParams);
}
Maksim Shamihulau
  • 1,219
  • 1
  • 15
  • 17
2

I think you can pass it BindingFlags.NonPublic where it is the GetMethod method.

Armin Ronacher
  • 31,998
  • 13
  • 65
  • 69
2

Could you not just have a different Draw method for each type that you want to Draw? Then call the overloaded Draw method passing in the object of type itemType to be drawn.

Your question does not make it clear whether itemType genuinely refers to objects of differing types.

Peter Hession
  • 501
  • 5
  • 9
0

Read this (supplementary) answer (that is sometimes the answer) to understand where this is going and why some people in this thread complain that "it is still not working"

I wrote exactly same code as one of the answers here. But I still had an issue. I placed break point on

var mi = o.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance );

It executed but mi == null

And it continued behavior like this until I did "re-build" on all projects involved. I was unit testing one assembly while the reflection method was sitting in third assembly. It was totally confusing but I used Immediate Window to discover methods and I found that a private method I tried to unit test had old name (I renamed it). This told me that old assembly or PDB is still out there even if unit test project builds - for some reason project it tests didn't built. "rebuild" worked

T.S.
  • 18,195
  • 11
  • 58
  • 78