将IEnumerable转换为IEnumerable <t> </t>

时间:2009-05-01 18:44:22

标签: c# linq

我有一个类(Web控件),它具有IEnumerable类型的属性,并且希望使用LINQ来处理该参数。

有没有办法通过反射转换/转换/调用IEnumerable&lt; T&gt;在编译时不知道类型?

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) {}

4 个答案:

答案 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 });
    }
}