1

Let's say we have two public methods within a class:

public class SomeClass
{
    public bool DoSomething(int param1)
    {
        return param1 == 30;
    }

    public bool DoSomethingElse(int param1)
    {
        param1 *= 2;
        return param1 == 30;
    }
}

I could write the following code to get both of these methods using reflection:

MethodInfo[] methods = typeof(SomeClass).GetMethods(BindingFlags.Public | BindingFlags.Instance)
                       .Where(x => x.ReturnType == typeof(bool)
                              && x.GetParameters().Length == 1
                              && x.GetParameters()[0].ParameterType == typeof(int)).ToArray();

Let's say I only wanted DoSomethingElse, I could just use methods[1].

However, let's say they swapped places the next time this class is compiled. I would end up with DoSomething instead.

The only thing that separates these two methods, is that DoSomethingElse multiplies the parameters by 2 before checking.

Are there any other checks I can do with reflection to ensure I always get DoSomethingElse?

Note: The methods I'm looking for may have their names changed each time it is compiled, so simply searching for their name won't work either.

ThePerplexedOne
  • 2,920
  • 15
  • 30
  • 1
    You could decorate the method with a custom `Attribute`, then use LINQ to check the methods for that attribute. – Prime Jan 30 '20 at 14:24
  • @AlphaDelta I'm not the one writing the source code. I don't have control over that. – ThePerplexedOne Jan 30 '20 at 14:25
  • 1
    I don't see anyway to do this with simple C# reflection. Maybe a usecase for [Cecil](https://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cecil/). A simple example that could fit your usage : https://stackoverflow.com/questions/49923757/mono-cecil-simple-example-how-to-get-method-body – rak007 Jan 30 '20 at 14:27
  • 1
    There are many things you could check, such as the method signature (parameters), return type, or even an analysis of the IL code of the method itself. But I'm not sure what you're asking is possible, given you aren't in control of the source; all potential metadata is mutable. – Prime Jan 30 '20 at 14:28
  • 2
    The actual question here is what metadata stays **constant**. If you can asnwer that, you can answer your question. We can´t. – MakePeaceGreatAgain Jan 30 '20 at 14:30
  • @HimBromBeere I think you might be right. I don't think it's possible with simple reflection. – ThePerplexedOne Jan 30 '20 at 14:31
  • Invoke them both with `30` and see which ends up returning true? But jokes aside, if there isn't anything logical or constant I really can't see a way to determine which is which. –  Jan 30 '20 at 14:45
  • I don't know what are you really trying to do but reflection give you only the metadata about the method and not the implementation details(lines of code). You can add custom attribute to the method. – Lior Jan 30 '20 at 14:54
  • @lior reflection enables reading the source code as it was originaly (the compiler may have optimized some of the code though) – nalka Jan 30 '20 at 14:56

1 Answers1

3

Technically, you can analyze methods' IL code; let's check if we have a * 2 within first 10 IL codes:

https://en.wikipedia.org/wiki/List_of_CIL_instructions

Code:

  MethodInfo[] methods = GetType()
    .GetMethods(BindingFlags.Public | BindingFlags.Instance)
    .Where(x => x.ReturnType == typeof(bool)
           && x.GetParameters().Length == 1
           && x.GetParameters()[0].ParameterType == typeof(int))
    .Where(m => m
       .GetMethodBody()
       .GetILAsByteArray()
       .Take(10)                  // take first 10 IL codes
       .SkipWhile(b => b != 0x18) // ldc.i4.2 : load 2
       .Any(b => b == 0x5A))      // mul      : multiply 
    .ToArray();

let's have a look:

  Console.Write(string.Join(Environment.NewLine, methods.Select(m => m.Name)));

Outcome:

  DoSomethingElse

however, I strongly recommend either use specific method Name or mark method with an attribute etc.

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215