6

Let's say there is a class A with an parameterless instance method

class A
{
    public A(int x) { this.x = x; }
    private int x;
    public int foo() { return x; }
}

It's easy to invoke the method using reflection:

A a = new A(100);
var method = typeof(A).GetMethod("foo");
var result = method.Invoke(a, new object[0]); // 100

However, I want to invoke the method as if it is static

var staticmethod = Something(typeof(A), "foo");
var result = staticmethod.Invoke(null, new object[] { a });

Is there any way I can get this staticmethod?

NOTE: I want Something to be universal, i.e. A can be any class, and foo can be any instance method.

EDIT: To make things clear:

There is no static method in class A.

There is a parameterless instance method called foo.

I want to invoke (using MethodInfo.Invoke) foo AS IF it is a static method, that takes class A as the parameter.

EDIT2: Why I want this: (to help you understand better)

I have a list of static methods that does similar job for different types, and they are stored in a dictionary Dictionary<Type, MethodInfo> dict.

Thus, whenever I have an object obj and want to do the job, I can

dict[obj.GetType()].Invoke(null, new object[] { obj, param1, param2, ... });

Now I want to add instance methods into it as well, but it will require me to remember which methods are static and which methods are instance-bond, and invoke them in different ways:

dict[obj.GetType()].Invoke(null, new object[] { obj, param1, param2, ... }); // static methods
dict[obj.GetType()].Invoke(obj, new object[] { param1, param2, ... }); // instance methods

Which is inconvenient. So I want to get static MethodInfo from instance methods, before adding them into the dict.

EDIT3: I don't understand why this question is marked duplicate. The linked page does NOT answer my question. If I'm missing something, please tell me.

The linked page has several answers, but they either

  1. requires that I know how many arguments foo takes, or
  2. gives a method that takes object[] as the parameter, instead of a list of parameters.

So none of them fit here.

After some research I found that there's something close to what I need:

 A a = new A(100);
 var method = typeof(A).GetMethod("foo");
 var deleg = Delegate.CreateDelegate(typeof(Func<A, int>), method)
 var result = deleg.DynamicInvoke(new object[] { a }); // 100

Here, it takes new object[] { a } as the argument. But the thing is, since I don't know how foo looks like, how can I pass the first argument of Delegate.CreateDelegate?

Last EDIT: Found a solution myself. Thank you for your help guys!

Will Vousden
  • 32,488
  • 9
  • 84
  • 95
Michael Kim
  • 689
  • 5
  • 20

2 Answers2

6

but it will require me to remember which methods are static and which methods are instance-bond, and invoke them in different ways

No need to remember it because the method knows this itself:

MethodInfo mi = GetTheMethodFromSomewhere();
object[] args = new object[] { obj, param1, param2, … };
if (mi.IsStatic)
    mi.Invoke(null, args);
else
    mi.Invoke(args[0], args.Skip(1).ToArray());
poke
  • 369,085
  • 72
  • 557
  • 602
  • This is exactly what I don't want... You ARE invoking them in different ways – Michael Kim Sep 14 '15 at 07:42
  • 1
    Well, you *cannot* do it without invoking them differently. They *have* to be invoked differently because they are fundamentally different. Every other way you will come up with (like `DynamicInvoke`) will encapsulate the different invokation in some way too. – poke Sep 14 '15 at 08:09
  • Well I'm not talking about the underlying mechanism of invoking methods, but how to invoke a method by code - and my answer looks just fine. By the way, I really doubt that the underlying mechanism is different, it's just an implicit "this" first parameter – Michael Kim Sep 14 '15 at 09:18
  • My point is, since I will be invoking the methods a LOT, I need to do anything to simplify the invoking code - I don't want to write this if-else a thousand times, so I MUST come up with a way to get things unified at the point of adding those methods. Writing another method to encapsulate the difference upon invocation is no-go in my case (although in my answer it's possible) – Michael Kim Sep 14 '15 at 09:27
  • @MichaelKim `DynamicInvoke` might *look* fine, but [it’s really not](http://stackoverflow.com/q/12858340/216074). You have *all* the information necessary to decide whether you need to call the method statically or not. Taking the extra route by creating a dynamic delegate will only add a lot of extra burden on the runtime which is unecessary. You haven’t given a single reason why branching the invoke would be a problem, and if you would just wrap that in a method, there is no difference in *using* it; but you get a lot better performance. – poke Sep 14 '15 at 09:28
  • *“I don't want to write this if-else a thousand times”* – So instead, you use the hundreds if-elses and additional checks that are included in DynamicInvoke… since you *“will be invoking the methods a LOT”*, you maybe should look at the performance of your “solution”. – poke Sep 14 '15 at 09:30
  • I don't want to WRITE this if-else a thousand time. I care more about simplification of my code than performance, get it? – Michael Kim Sep 14 '15 at 09:36
  • He said you can wrap the logic in a method, so you won't be writing it a thousand times. Get it? – Rob Grant Sep 14 '15 at 09:54
-1

Static methods and instance methods can be unified by creating a delegate, and then calling DynamicInvoke:

Dictionary<Type, Delegate> dict = new Dictionary<Type, Delegate>();

void AddMethod(Type type, String methodName)
{
    var method = type.GetMethod(methodName);
    var types = method.GetParameters().ConvertAll(p => p.ParameterType).ToList();
    if (!method.IsStatic)
        types.Insert(0, type);
    types.Add(method.ReturnType);
    var delegType = Expression.GetFuncType(types.ToArray());
    var deleg = method.CreateDelegate(delegType);
    dict.Add(type, deleg);
}

object GetJobResult(object obj, params object[] additionalParams)
{
    var paramList = additionalParams.ToList();
    paramList.Insert(0, obj);
    return dict[obj.GetType()].DynamicInvoke(paramList.ToArray());
}
Michael Kim
  • 689
  • 5
  • 20