Frank Krueger
Frank Krueger

Reputation: 70983

How to invoke methods with ref/out params using reflection

Imagine I have the following class:

class Cow {
    public static bool TryParse(string s, out Cow cow) {
        ...
    }
}

Is it possible to call TryParse via reflection? I know the basics:

var type = typeof(Cow);
var tryParse = type.GetMethod("TryParse");

var toParse = "...";

var result = (bool)tryParse.Invoke(null, /* what are the args? */);

Upvotes: 12

Views: 6479

Answers (2)

Stephan Ennen
Stephan Ennen

Reputation: 39

Sorry for the bump, but the previous answers to this thread got me started but did not fully answer what I needed. Here's the rest of the answer I figured out:

When working with reflection, in, out, and ref method parameter types are all the same kind of special "ref" type which you can get by doing typeof(MyType).MakeByRefType(). When searching for methods with matching parameter types, MyType and ref MyType are considered to be not equal!

Below code is what I did to add a TryParse method to my class that holds a generic struct TData. My TryParse reflectively searches for TData's TryParse and tries to invoke that, instead of having to manually implement a TryParse override method for each held TData struct type.

(try;catch; and some other stuff removed for readability)

public bool TryParse(string stringToParse, out TData outResult)
{
    // Given 'TData' is the type we want to try to invoke TryParse() on...
    const string METHOD_NAME = "TryParse";
    Type type = typeof(TData);
    Type[] methodParams = new[] { typeof(string), type.MakeByRefType() }; //GetMethod() will fail without MakeByRefType() here!
    MethodInfo method = type.GetMethod(METHOD_NAME, BindingFlags.Static | BindingFlags.Public, null, methodParams, null);

    TData outResult = default(TData);
    if (method == null) 
        return false;

    // TryParse "out TData" gets written to object[1] array after invoke.
    object[] invokeParams = new object[] { stringToParse, outResult };
    object result = method.Invoke(null, invokeParams);

    if (result is bool didParse && didParse)
    {
        outResult = (TData)invokeParams[1]; //Read what the method wrote as "out TData"
        return true; // return parse success
    }
    return false;
}

Upvotes: 1

azamsharp
azamsharp

Reputation: 20066

You can do something like this:

static void Main(string[] args)
{
    var method = typeof (Cow).GetMethod("TryParse");
    var cow = new Cow();           
    var inputParams = new object[] {"cow string", cow};
    method.Invoke(null, inputParams); 
    // out parameter value is then set in inputParams[1]
    Console.WriteLine( inputParams[1] == null ); // outputs True
}

class Cow
{
    public static bool TryParse(string s, out Cow cow) 
    {
        cow = null; 
        Console.WriteLine("TryParse is called!");
        return false; 
    }
}

Upvotes: 10

Related Questions