Return Out Variables Using GetMethod

So I ran into a problem today. I wanted to call a method (TryParse) off a type using relfection, but the catch is that there is an out parameter. At first I though, “Hey, I just give it the type and it will find it. Not so lucky. See when you call GetMethod you have to supply a list of parameters. why? because if you don’t, the name alone could return any number of methods named the same thing. By using a parameter list, it in essence narrows it down to one. Say you look at decimal.TryParse which expects a string and an out parameter of type decimal. Would think it is:

  Type[] paramTypes = new Type[2] { typeof(string), typeof(decimal) };
  returnValue = typeToCheck.GetMethod("TryParse", paramTypes);

No dice. Looks ok until you actually look at the type of the second parameter. It’s actually “decimal&”, meaning there is a reference attached to it. This makes sense since Out will switch the pointer of the old parameter sent in to whatever you create in the method. Problem is when you trying to find the method you are looking for “decimal” != “decimal&”. Now this looks like a big problem, but it’s actually easy to solve.

  Type[] paramTypes = new Type[2] { typeof(string), typeof(decimal).MakeByRefType() };

See the difference? Turns out Microsoft already thought this one through. The MakeByRefType method allows you to simulate an out parameter. Here’s the method in full to get the MethodInfo:

  private static MethodInfo GetCorrectMethodInfo(Type typeToCheck)
  {
    //This line may not mean much but with reflection, it's usually a good idea to store
    //things like method info or property info in a cache somewhere so that you don't have
    //have to use reflection every time to get what you need.  That's what this is doing.
    //Basically I am using the passed in type name as the key and the value is the methodInfo
    //for that type.
    MethodInfo returnValue = someCache.Get(typeToCheck.FullName);

    //Ok, now for the reflection part.
    if(returnValue == null)
    {
      Type[] paramTypes = new Type[2] { typeof(string), typeToCheck.MakeByRefType() };
      returnValue = typeToCheck.GetMethod("TryParse", paramTypes);
      if (returnValue != null)
      {
        someCache.Add(typeToCheck.FullName, returnValue);
      }
    }

    return returnValue;
  }

Now we’re not done yet, are we? No. That just gets the methodInfo needed. Now how do I call it and get a value back? Well that’s pretty easy too:

  MethodInfo neededInfo = GetCorrectMethodInfo(typeof(decimal));
  decimal output = new decimal();
  object[] paramsArray = new object[2] { numberToConvert, output };
  object returnedValue = neededInfo.Invoke(returnValue.Value, paramsArray);

  if (returnedValue is bool && (bool)returnedValue)
  {
      returnValue = (decimal)paramsArray[1];
  }
  else
  {
    returnValue = null;
  }

So first part is actually calling the method we now have:

  MethodInfo neededInfo = GetCorrectMethodInfo(typeof(decimal));
  decimal output = new decimal();
  object[] paramsArray = new object[2] { numberToConvert, output };
  object returnedValue = neededInfo.Invoke(returnValue, paramsArray);

So basically you take the variables, put them into an array, and then pass that array trough the invoke method. Nice thing is when the two variables are sent into the method, you don’t have to flag output as an Out parameter.

Now for the FINALLY ITS OVER

  if (returnedValue is bool && (bool)returnedValue)
  {
      returnValue = (decimal)paramsArray[1];
  }
  else
  {
    returnValue = null;
  }

You would think that the “output” variable you sent through .Invoke would hold the needed value. Too bad. You actually have to look at the object array passed in to get the value of the Out parameter. Kind of annoying, but deal with it.

And there you have it, how to not only find a methodInfo with an out parameter, but how to get the value back too. YAY

  using System;
  using System.Reflection;

My next post will show why I had to figure this out and I promise it will be worth it.

1 thought on “Return Out Variables Using GetMethod”

Comments are closed.