Отражение: тип элемента, содержащегося в неуниверсальном подклассе общего списка - PullRequest
2 голосов
/ 25 января 2012
public class MyList : List<MyClass>

Как я могу получить тип MyClass через отражение, если у меня есть object, который содержит экземпляр MyList? Список может быть пустым, поэтому я не могу сделать что-то вроде myList[0].GetType().

p.s. Я не могу просто перестать использовать MyList и вместо этого напрямую использовать универсальный список (ситуация немного сложнее, и есть причины «скрывать» универсальный аргумент), поэтому я не могу подобрать MyClass через GetGenericArguments().

Ответы [ 4 ]

7 голосов
/ 25 января 2012
var elementType = (
    from iface in myList.GetType().GetInterfaces()
    where iface.IsGenericType
    where iface.GetGenericTypeDefinition() == typeof(IList<>)
    select iface.GetGenericArguments()[0])
        .Single();

Я использую IList<T> вместо списка. Это более общее. Однако есть также изменение типа, реализующего несколько версий ILis<T> (например, IList<string> и IList<int>).

1 голос
/ 25 января 2012

Вы можете получить базовый тип, который будет List<MyClass>; из него вы можете получить аргумент универсального типа с помощью GetGenericArguments .

0 голосов
/ 25 января 2012

Ваш класс реализует универсальные интерфейсы? Вы можете использовать следующий код:

Type argument = GetGenericArgument(typeof(MyList), typeof(IList<>));
//...
static Type GetGenericArgument(Type type, Type genericTypeDefinition) {
    Type[] interfaces = type.GetInterfaces();
    for(int i = 0; i < interfaces.Length; i++) {
        if(!interfaces[i].IsGenericType) continue;
        if(interfaces[i].GetGenericTypeDefinition() == genericTypeDefinition)
            return interfaces[i].GetGenericArguments()[0];
    }
    return null;
}

Без интерфейсов вы можете попробовать следующее:

class A { }
class B { }
class G<T> { }
class G1<T> : G<A> { }
class G2 : G1<B> { }
//...
Type argument1 = GetGenericArgument(typeof(G2)); // B
Type argument2 = GetGenericArgument(typeof(G2),1 ); // A
//...
static Type GetGenericArgument(Type type, int level = 0) {
    do {
        if(type.IsGenericType && 0 == level--)
            return type.GetGenericArguments()[0];
        type = type.BaseType;
    }
    while(type != null);
    return null;
}
0 голосов
/ 25 января 2012
MyList list = new MyList();
Type baseTypeGenericArgument = list.GetType().BaseType.GetGenericArguments()[0];
string argumentTypeName = baseTypeGenericArgument.GetType().FullName;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...