问题描述:

I am trying to write a generic extension method targeting .Net 4.5. I want to test a type to see if TryParse is defined in the class. If yes, invoke the TryParse method at runtime.

Here is my implemenation.

using System;

using System.Linq;

using System.Reflection;

namespace ExtentionMethodPractises

{

static public class ExtensionMethods

{

public static T ParseOrDefault<T>(this T targetType, string source) where T : new()

{

if (targetType.GetType().GetMethods(BindingFlags.Static|BindingFlags.Public).Any(methodInfo => methodInfo.Name == "TryParse"))

{

var result = new T();

var parameterTypes = new Type[] {source.GetType(), targetType.GetType()};

var parameterModifier = new ParameterModifier(2);

parameterModifier[0] = false;

parameterModifier[1] = true;

var tryParseMethod = targetType.GetType().GetMethod("TryParse", parameterTypes, new ParameterModifier[] { parameterModifier});

tryParseMethod.Invoke(null, new object[] {source, result});

return result;

}

return new T();

}

}

}

I tested my extension method with System.UInt16 which has TryParse methods. I got a nullref on the tryParseMethod after reflection.

I implemented a dummy test class ReflectorTarget to test my extension method. I got a null reference too. It seems that the reflector is incapable of search methods has pass-by-reference parameter(s).

namespace ExtentionMethodPractises

{

public class ReflectorTarget

{

public static bool TryParse(string source, out ReflectorTarget output)

{

output = new ReflectorTarget();

return true;

}

public static bool TryParse(string source, bool isReally, out ReflectorTarget output)

{

output = new ReflectorTarget();

return true;

}

}

}

Lastly, I changed my dummy test class implementation as follows. Suddenly, the reflector will pick up the TryParse method at runtime. All I did is change the second parameter from a pass-by-reference parameter to a normal parameter.

namespace ExtentionMethodPractises

{

public class ReflectorTarget

{

public static bool TryParse(string source, ReflectorTarget output)

{

return true;

}

public static bool TryParse(string source, bool isReally, out ReflectorTarget output)

{

output = new ReflectorTarget();

return true;

}

}

}

Question: How do I reflect a method (static/non-static) that has a pass-by-reference parameter in C#? Thank you.

网友答案:

I think you want this:

namespace ExtentionMethodPractises
{
    static public class ExtensionMethods
    {
        public static T ParseOrDefault<T>(this T targetType, string source)
            where T : new()
        {
            if (targetType.GetType()
                .GetMethods(BindingFlags.Static|BindingFlags.Public)
                .Any(methodInfo => methodInfo.Name == "TryParse"))
            {
                var result = new T();

                var parameterTypes = new Type[] {source.GetType(),

                          //Key change here
                          targetType.GetType().MakeByRefType()};

                var tryParseMethod = targetType.GetType()
                    .GetMethod("TryParse", parameterTypes);

                tryParseMethod.Invoke(null, new object[] {source, result});

                return result;
            }

            return new T();
        }
    }
}

see MakeByRefType:

Returns a Type object that represents the current type when passed as a ref parameter (ByRef parameter in Visual Basic).

网友答案:
   tryParseMethod.Invoke(null, new object[] {source, result});

Damien got you unblocked on passing the correct type, but you still need to invoke the method correctly. A method that takes a ref argument will update the value in the passed object[], it is not going to modify your result variable. And you are interested in the return value of this method. Also notable is that ParameterModifier is actually ignored for .NET methods. Which collapses your method down to:

public static T ParseOrDefault<T>(this T targetType, string source) where T : new() {
    var parameterTypes = new Type[] { source.GetType(), targetType.GetType().MakeByRefType() };
    var tryParseMethod = targetType.GetType().GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, parameterTypes, null);
    if (tryParseMethod != null) {
        var args = new object[] { source, null };
        var retval = (bool)tryParseMethod.Invoke(null, args);
        if (retval) return (T)args[1];
    }
    return new T();
}
相关阅读:
Top