Convert/Cast IEnumerable to IEnumerable <T>
У меня есть класс (веб-элемент управления), который имеет свойство типа IEnumerable и хотел бы работать с параметром с помощью LINQ.
Есть ли способ кастать/конвертировать/вызывать через отражение в IEnumerable <T> не зная тип во время компиляции?
Method void (IEnumerable source)
{
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
{
var type = enumerator.Current.GetType();
Method2<type>(source); // this doesn't work! I know!
}
}
void Method2<T>(IEnumerable<T> source) {}
Ответы
Ответ 1
Действительно ли ваш Method2
какой тип он получает? Если нет, вы можете просто вызвать Cast<object>()
:
void Method (IEnumerable source)
{
Method2(source.Cast<object>());
}
Если вам определенно нужно получить правильный тип, вам нужно будет использовать отражение.
Что-то вроде:
MethodInfo method = typeof(MyType).GetMethod("Method2");
MethodInfo generic = method.MakeGenericMethod(type);
generic.Invoke(this, new object[] {source});
Это не идеально, хотя... в частности, если источник не является точно IEnumerable<type>
, тогда вызов будет терпеть неудачу. Например, если первый элемент является строкой, но источником является List<object>
, у вас возникнут проблемы.
Ответ 2
Вероятно, вы захотите реорганизовать свой код для использования IEnumerable.Cast<T>
Используйте его следующим образом:
IEnumerable mySet = GetData();
var query = from x in mySet.Cast<int>()
where x > 2
select x;
Ответ 3
С .NET 4 вы можете просто передать source
в dynamic
, прежде чем передавать его методу. Это приведет к разрешению правильной общей перегрузки во время выполнения без какого-либо уродливого кода отражения:
void Method(IEnumerable source)
{
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
{
Method2((dynamic)source);
}
}
Как и во втором решении Jon, это будет работать, только если ваш источник - это IEnumerable<T>
. Если это простой IEnumerable
, вам нужно создать другой метод, который преобразует его в правильный тип IEnumerable<T>
, как в следующем решении:
IEnumerable<T> Convert<T>(IEnumerable source, T firstItem)
{
// Note: firstItem parameter is unused and is just for resolving type of T
foreach(var item in source)
{
yield return (T)item;
}
}
void Method(IEnumerable source)
{
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
{
dynamic firstItem = enumerator.Current;
dynamic typedEnumerable = Convert(source, firstItem);
Method2(typedEnumerable);
}
}
Ответ 4
Это несколько лет спустя, но я решил проблему List<Object>
.
void Method(IEnumerable source)
{
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
{
MethodInfo method = typeof(MyClass).GetMethod("Method2");
MethodInfo generic;
Type type = enumerator.Current.GetType();
bool sameType = true;
while (enumerator.MoveNext())
{
if (enumerator.Current.GetType() != type)
{
sameType = false;
break;
}
}
if (sameType)
generic = method.MakeGenericMethod(type);
else
generic = method.MakeGenericMethod(typeof(object));
generic.Invoke(this, new object[] { source });
}
}