将IEnumerable转换/转换为IEnumerable <T>
我有一个类(一个Web控件)具有IEnumerabletypes的属性,并希望使用LINQ的参数。
有没有办法通过reflection投入/转换/调用IEnumerable <T>不知道编译时的types?
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) {}
你的Method2
真的关心它的types吗? 如果没有,你可以调用Cast<object>()
:
void Method (IEnumerable source) { Method2(source.Cast<object>()); }
如果你确实需要得到正确的types,你需要使用reflection。
就像是:
MethodInfo method = typeof(MyType).GetMethod("Method2"); MethodInfo generic = method.MakeGenericMethod(type); generic.Invoke(this, new object[] {source});
这并不理想,特别是,如果源不完全是一个IEnumerable<type>
那么调用将失败。 例如,如果第一个元素碰巧是一个string,但是源代码是一个List<object>
,则会遇到问题。
您可能想要重构您的代码以使用IEnumerable.Cast<T>
像这样使用它:
IEnumerable mySet = GetData(); var query = from x in mySet.Cast<int>() where x > 2 select x;
使用.NET 4,您只需将source
传递给方法即可。 这将导致正确的generics重载在运行时被parsing,没有任何难看的reflection代码:
void Method(IEnumerable source) { var enumerator = source.GetEnumerator(); if (enumerator.MoveNext()) { Method2((dynamic)source); } }
和Jon的第二个解决scheme一样,只有当你的源代码实际上是一个IEnumerable<T>
才会有效。 如果它是一个纯IEnumerable
那么您将需要创build另一个方法,将其转换为正确的IEnumerable<T>
types,如下面的解决scheme:
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); } }
这是几年后,但我解决了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 }); } }