我有一个类(Web控件),它具有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) {}
答案 0 :(得分:64)
你的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});
虽然这并不理想......特别是,如果source不是完全 IEnumerable<type>
,那么调用将失败。例如,如果第一个元素恰好是一个字符串,但是源是List<object>
,那么你就会遇到问题。
答案 1 :(得分:10)
您可能希望重构代码以使用IEnumerable.Cast<T>
像这样使用:
IEnumerable mySet = GetData();
var query = from x in mySet.Cast<int>()
where x > 2
select x;
答案 2 :(得分: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);
}
}
答案 3 :(得分:2)
这是多年以后,但我解决了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 });
}
}