Приведение с использованием Reflection в C # - PullRequest
4 голосов
/ 28 февраля 2011

Я создал обобщенную функцию, как показано ниже (просто доказательство), которая примет коллекцию List<T> и обратит ее, вернув новый List<T> в качестве вывода.

public static List<T> ReverseList<T>(List<T> sourceList)
{
    T[] outputArray = new T[sourceList.Count];
    sourceList.CopyTo(outputArray);
    return outputArray.Reverse().ToList();
}

Цель доказательства в том, что я знаю только, что такое T во время выполнения. Поэтому я использую рефлексию для вызова вышеуказанного метода следующим образом:

List<int> myList = new List<int>() { 1, 2, 3, 4, 5 }; // As an example, but could be any type for T

MethodInfo myMethod = this.GetType().GetMethod("ReverseList");
MethodInfo resultMethod = myMethod.MakeGenericMethod(new Type[] { typeof(int) });
object result = resultMethod.Invoke(null, new object[] { myList });

Здесь есть две проблемы:

  1. Во второй строке, вместо того, чтобы указывать typeof(int), я бы хотел, чтобы somthign сродни myList.GetType().GetGenericArguments()[0].GetType(), чтобы сделать вещи более гибкими, потому что я не знаю T до времени выполнения. Это приводит к ошибке времени выполнения, когда Invoke выполняется следующим образом: «Объект типа« System.Collections.Generic.List'1 [System.Int32] »не может быть преобразован в тип« System.Collections.Generic.List'1 [ System.RuntimeType] ".
  2. Результат метода Invoke() возвращает объект. При отладке я вижу, что объект относится к типу List, но попытка использовать его говорит мне, что у меня неверное приведение. Я предполагаю, что мне нужно использовать отражение, чтобы связать результат с правильным типом (то есть в этом примере, эквивалент (result as List<int>).

У кого-нибудь есть указатели, которые могли бы помочь мне решить эту проблему? Извиняюсь, если это не ясно, я могу предоставить более подробную информацию, если вас спросят.

ТИА

Ответы [ 3 ]

5 голосов
/ 28 февраля 2011

У вас есть один GetType() слишком много.Бывает со всеми.

myList.GetType().GetGenericArguments()[0] - это System.Type - тот, который вы ищете.

myList.GetType().GetGenericArguments()[0].GetType() - это System.Type, описывающий System.Type (ну, на самом делеконкретный подкласс System.RuntimeType).


Кроме того, ваша функция ReverseList серьезно излишня.Он делает лишнюю копию, чтобы не вызывать List.Reverse.Есть лучший способ обойти это:

public static List<T> ReverseList<T>(List<T> sourceList)
{
    return Enumerable.Reverse(sourceList).ToList();
}

или

public static List<T> ReverseList<T>(List<T> sourceList)
{
    var result = new List<T>(sourceList);
    result.Reverse();
    return result;
}

или

public static List<T> ReverseList<T>(List<T> sourceList)
{
    var result = new List<T>();
    result.Capacity = sourceList.Count;
    int i = sourceList.Count;
    while (i > 0)
        result.Add(sourceList[--i]);
    return result;
}
3 голосов
/ 28 февраля 2011

Чтобы получить доступ к нему как List<T>, да, вам нужно найти T, используя отражение (возможно, через интерфейсы, например, typeof(IList<>)), и использовать больше отражений и MakeGenericMethod и т. Д. Честно говоря, это не так. оно того стоит: вам лучше проверить неуниверсальный IList:

var list = result as IList;
if (list != null)
{
    // loop over list etc
}

Отражение рекламы дженериков - не хорошие друзья.

Обратите внимание, что в 4.0 есть также некоторые приемы, которые вы можете сделать здесь с помощью dynamic и обобщений.

1 голос
/ 28 февраля 2011

Результат метода Invoke () возвращает объект.При отладке я вижу, что объект относится к типу List, но попытка использовать его говорит мне, что у меня неверное приведение.Я предполагаю, что мне нужно использовать отражение, чтобы связать результат с правильным типом (то есть в этом примере, эквивалентным (результат как список).

Единственный обходной путь для этого, я могу думатьиз это передать пустой список в качестве второго параметра метода и заполнить этот список - ссылка, возвращаемая Invoke(), будет всегда иметь только тип объекта, но внутри универсального метода у вас есть доступк самому типу:

List<int> reverseList = new List<int>();
resultMethod.Invoke(null, new object[] { myList, reverseList });

...

public static void ReverseList<T>(List<T> sourceList, List<T> resultList)
{
    T[] outputArray = new T[sourceList.Count];
    sourceList.CopyTo(outputArray);
    resultList.AddRange(outputArray.Reverse());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...