Отражение в статическом перегруженном методе с использованием параметра out - PullRequest
14 голосов
/ 19 января 2011

У меня есть некоторые проблемы с вызовом перегруженного статического метода с параметром out через отражение, и я буду признателен за некоторые указатели.

Я хочу динамически создать тип, такой как System.Int32 или System.Decimal, а затем вызвать статический метод TryParse(string, out x) для него.

В приведенном ниже коде есть две проблемы:

  • t.GetMethod("TryParse", new Type[] { typeof(string), t } ) не удалось вернуть ожидаемое MethodInfo

  • mi.Invoke(null, new object[] { value.ToString(), concreteInstance }) кажется успешным, но не устанавливает выходной параметр concreteInstance в разобранное значение

В этой функции вы можете увидеть временный код, демонстрирующий, что должно произойти, если для параметра type установлено значение System.Decimal.

public static object Cast(object value, string type)
{
    Type t = Type.GetType(type);
    if (t != null)
    {
        object concreteInstance = Activator.CreateInstance(t);
        decimal tempInstance = 0;

        List<MethodInfo> l = new List<MethodInfo>(t.GetMethods(BindingFlags.Static | BindingFlags.Public));

        MethodInfo mi;
        mi = t.GetMethod("TryParse", new Type[] { typeof(string), t } );  //this FAILS to get the method, returns null
        mi = l.FirstOrDefault(x => x.Name == "TryParse" && x.GetParameters().Length == 2);  //ugly hack required because the previous line failed
        if (mi != null)
        {
            try
            {
                bool retVal = decimal.TryParse(value.ToString(), out tempInstance);
                Console.WriteLine(retVal.ToString());       //retVal is true, tempInstance is correctly set
                object z = mi.Invoke(null, new object[] { value.ToString(), concreteInstance });
                Console.WriteLine(z.ToString());            //z is true, but concreteInstance is NOT set
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

        return concreteInstance;
    }

    return value;
}

Что мне нужно сделать, чтобы мой t.GetMethod() вызов вернул правильную MethodInfo? Что мне нужно сделать, чтобы правильно установить concreteInstance в моем вызове mi.Invoke()?

Я знаю, что есть множество вопросов по этой теме, но большинство из них включают статические обобщенные методы или статические методы, которые не перегружены. Этот вопрос похож, но не является дубликатом.

1 Ответ

27 голосов
/ 19 января 2011

Вам нужно использовать правильные BindingFlags и использовать Type.MakeByRefType для out и ref параметров. Одна секунда, и у меня будет для вас пример кода.

Например,

MethodInfo methodInfo = typeof(int).GetMethod(
    "TryParse",
    BindingFlags.Public | BindingFlags.Static,
    Type.DefaultBinder,
    new[] { typeof(string), typeof(int).MakeByRefType() },
    null
);

Я должен отметить, что вызывать это тоже немного сложно. Вот как ты это делаешь.

string s = "123";
var inputParameters = new object[] { "123", null };
methodInfo.Invoke(null, inputParameters);
Console.WriteLine((int)inputParameters[1]);

Первый null заключается в том, что мы вызываем статический метод (нет объекта, «получающего» этот вызов). null в inputParameters будет «заполнен» для нас на TryParse результатом анализа (это параметр out).

...