3

Similar to a previous question of mine, when I was asking about getting the FieldInfo of a field, How to get the FieldInfo of a field from the value, from the answers there, I compiled this helper class,

using System;
using System.Reflection;
using System.Linq.Expressions;

internal class Program
{
    class MyClass
    {
#pragma warning disable 0414, 0612, 0618, 0649
        private int myInt = 24;
#pragma warning restore 0414, 0612, 0618, 0649

        public const BindingFlags _flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

        public MyClass()
        {
            MemberInfo myIntMI = GetMemberInfo(this, c => c.myInt);
            Console.WriteLine(myIntMI.Name + ": " + GetFieldValue(myIntMI) + ", " + GetFieldInfo(myIntMI).FieldType);

//          MemberInfo tfMI = GetMemberInfo(this, cw => cw.testFunction());
//          MemberInfo tfMI = GetMemberInfo(this, cw => cw.testFunction);
//          Console.WriteLine(tfMI.Name + ": " + GetFieldValue(tfMI) + ", " + GetFieldInfo(tfMI).FieldType);

            foreach( var mi in GetType().GetMethods(_flags) )
            {
                Console.WriteLine("method: " + mi);
            }
        }

        private void testFunction() { }

        private object GetFieldValue(MemberInfo mi)
        {
            return GetFieldInfo(mi).GetValue(this);
        }

        private FieldInfo GetFieldInfo(MemberInfo mi)
        {
            return GetType().GetField(mi.Name, _flags);
        }

        private MemberInfo GetMemberInfo<TModel, TItem>(TModel model, Expression<Func<TModel, TItem>> expr)
        {
            return ( (MemberExpression)expr.Body ).Member;
        }
    }
}

Which works perfectly well using the GetMemberInfo(this, c => c.myInt, but the commented out line is what I'm confused about now, GetMemberInfo(this, c => c.testFunction) or GetMemberInfo(this, c => c.testFunction()).

Is there any way, without string comparison, I can get the member info that's available from a GetMethods() runthrough, or GetMethod("testFunction")?

Community
  • 1
  • 1
seaders
  • 3,878
  • 3
  • 40
  • 64
  • I think (but am not in a position to verify) that to be able to pass `c => c.testFunction()` to `GetMemberInfo`, the type of the second parameter would have to be `Expression>`. To be able to pass `c => c.testFunction`, I *think* your parameter would have to be of type `Expression>`. Since `testFunction` doesn't have a return type, `TItem` wouldn't play a role. – Ann L. Mar 11 '15 at 12:35

1 Answers1

2

MemberExpression is only for properties and fields. You probably look at MethodCallExpression.

So something like

((MethodCallExpression)expr.Body).Method

assuming that you pass a lambda that looks like () => this.testFunction()

So to get the MemberInfo you would get a Method property of a MemberCallExpression.

Also, you should then change the GetMemberInfo method signature, because this is a lambda that takes no parameters and returns the same type that your method returns, so it will be a private MemberInfo GetMemberInfo<T>(Expression<Func<T, void>> expr) or something close to it.

I'm not 100% sure, but what happens is, this.testFunction is actually a syntactic sugar for delegate creation, so it's actually something like new Action(this.testFunction) assuming testFunction is void testFunction(). Or something like this, because this.testFunction is not a member access, but rather a delegate creation.

JustSomeGuy
  • 3,677
  • 1
  • 23
  • 31
  • 1
    Shouldn't a method with a return type of `void` be an `Action` rather than `Func`? – Ann L. Mar 11 '15 at 12:43
  • 1
    But he can try to use this code for methods that can take parameters and return values. Lambda itself will most certainly have no parameters, but it will still have a return type of the method called. – JustSomeGuy Mar 11 '15 at 12:52
  • Perfect. I re-edited my question when I realised I wanted/needed MethodInfo rather than MemberInfo, but your answer is still correct (nearly). What I've used is `private MethodInfo GetMethodInfo(Expression expr) { return ( (MethodCallExpression)expr.Body ).Method; }` which is your answer, along with Ann's suggestion. Many thanks! – seaders Mar 11 '15 at 13:00
  • No problem. For some reason Expressions aren't documented very good and it's pretty easy to get lost with them – JustSomeGuy Mar 11 '15 at 13:05
  • I'd have that opinion about a huge amount of reflection in areas of C#, and if you hop onto IRC, or similar, I've found you get hammered for wanting to do that sort of thing. With Python, the docs were much better, and the community was a lot more open to that type of coding. – seaders Mar 11 '15 at 14:06