2

In my code I have some functions that call Type.GetMethod(string, Type[]) on some various static functions of the CLR. Maybe 30 or so different static functions are being looked up in total. But they are being looked up repeatedly and often because the parent functions are being called often. I assume the CLR would cache the MethodInfo results so only the first call for each unique looked-up method is costly, but I would like some confirmation.

EDIT: The MethodInfo results end up being arguments to Expression.Call() statements in Expression trees.

Would it be better/more dependable to implement my own cache? If I did so, can I cache the MethodInfo results once at the very start of the app, and just reaccess them indefinitely? Or should I use RuntimeMethodHandle instead like this:

// Obtaining a Handle from an MemberInfo
RuntimeMethodHandle handle = typeof(D).GetMethod("MyMethod").MethodHandle;
// Resolving the Handle back to the MemberInfo
MethodBase mb = MethodInfo.GetMethodFromHandle(handle);

That snippet comes from: https://msdn.microsoft.com/en-us/magazine/cc163759.aspx#S8

It's not clear to me why I would cache a RuntimeMethodHandle instead of just the MethodInfo.

leppie
  • 115,091
  • 17
  • 196
  • 297
Special Sauce
  • 5,338
  • 2
  • 27
  • 31
  • Are you going to call into the reflected methods? If so, the following post may be of interest: http://stackoverflow.com/questions/25458/how-costly-is-net-reflection -- look in particular at the reference tip about using a delegate to 'cache' a reflected method. – David Tansey Jun 03 '15 at 02:48
  • Edited my post to include this info. The `MethodInfo` is passed in as an argument to `Expression.Call()` which I assume creates a delegate on it. So my problem is not so much a speedy invocation as it is making sure the `Type.GetMethod()` calls are not incurring big hits every time they are being called on the same methods. – Special Sauce Jun 03 '15 at 02:53
  • AFAIK once looked up, it will be cached (per type I think). – leppie Jun 03 '15 at 08:10

1 Answers1

2

my problem is not so much a speedy invocation as it is making sure the Type.GetMethod() calls are not incurring big hits every time they are being called on the same methods

Then you will need to cache the MethodInfo object for a given method name. The CLR does not guarantee it will cache this for you, and indeed it can be very expensive to call GetMethod(), no matter how often you do it, depending on whether the data is still cached or not. Reflection in general is expensive. It should be eschewed if at all possible, especially when performance is a concern.

In your case, since you are dealing with Expression objects, depending on how exactly you're using them (without a good, minimal, complete code example it's not possible to know for sure what's best in your scenario), you may find it makes more sense to cache compiled expressions. More generally, obviously if you going to cache anything at all, it makes the most sense to cache the result farthest down your processing that is invariant for the cache key.

Note that the CLR does cache runtime member resolution for dynamic type objects. If you didn't want to mess with implementation of a cache yourself, it's possible you could incorporate dynamic into your expressions and let the CLR handle the caching of the dynamically-named methods. Again, without more details of your specific scenario, it's not possible to say for sure whether that would even work, never mind whether it's a useful approach in your case.

Community
  • 1
  • 1
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Your first and second sentences are the information I was trying to glean. The linked Microsoft article seemed to suggest this method was cached lazily behind the scenes. Can you comment on the difference between `RuntimeMethodHandle` and `MethodInfo`? In that linked article they showed using `RuntimeMethodHandle` exactly in the context of caching `Type.GetMethod()`. But why is `RuntimeMethodHandle` any better than `MethodInfo`? It seems like one more level of indirection. – Special Sauce Jun 03 '15 at 07:29
  • 1
    As the article says, the runtime does cache `MethodInfo` objects. But note that these are cached via weak references; the cached objects (and the cache itself) may well be reclaimed if you don't retain references to any `MethodInfo` objects in the cache, causing subsequent calls to `GetMethod()` to still be slow. The handle gives you a performance benefit in the case of a cache _miss_, as having the handle allows for faster retrieval of the actual `MethodInfo` object data than if the runtime had to do the work from scratch. But it's still not nearly as fast as caching yourself. – Peter Duniho Jun 03 '15 at 07:52
  • I've edited the question to try to make clearer the caching behavior. Note also that I don't have any information newer than the pre-2.0 article you reference, and this all could have changed in the interim. – Peter Duniho Jun 03 '15 at 07:55