C# 将 IEnumerable 转换/转换为 IEnumerable<T>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/812673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 02:11:39  来源:igfitidea点击:

Convert / Cast IEnumerable to IEnumerable<T>

c#linq

提问by andleer

I have a class (A web control) that has a property of type IEnumerable and would like to work with the parameter using LINQ.

我有一个类(一个 web 控件),它有一个 IEnumerable 类型的属性,并且想使用 LINQ 处理参数。

Is there any way to cast / convert / invoke via reflection to IEnumerable<T> not knowing the type at compile time?

有没有办法通过反射将/转换/调用转换为 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) {}

采纳答案by Jon Skeet

Does your Method2really care what type it gets? If not, you could just call Cast<object>():

Method2真的关心它是什么类型吗?如果没有,你可以打电话Cast<object>()

void Method (IEnumerable source)
{
    Method2(source.Cast<object>());
}

If you definitely need to get the right type, you'll need to use reflection.

如果您确实需要获得正确的类型,则需要使用反射。

Something like:

就像是:

MethodInfo method = typeof(MyType).GetMethod("Method2");
MethodInfo generic = method.MakeGenericMethod(type);
generic.Invoke(this, new object[] {source});

It's not ideal though... in particular, if source isn't exactlyan IEnumerable<type>then the invocation will fail. For instance, if the first element happens to be a string, but source is a List<object>, you'll have problems.

但它并不理想……特别是,如果源不完全是一个,IEnumerable<type>那么调用将失败。例如,如果第一个元素恰好是一个字符串,而 source 是 a List<object>,你就会遇到问题。

回答by Brian Genisio

You probably want to refactor your code to use IEnumerable.Cast<T>

您可能想要重构您的代码以使用 IEnumerable.Cast<T>

Use it like this:

像这样使用它:

IEnumerable mySet = GetData();
var query = from x in mySet.Cast<int>()
            where x > 2
            select x;

回答by Michael Anderson

This is years later, but I solved the List<Object>problem.

这是多年后,但我解决了这个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 });
    }
}

回答by luksan

With .NET 4 you can just cast sourceto dynamicbefore passing it to method. This will cause the correct generic overload to be resolved at runtime without any ugly reflection code:

在.NET 4中你只可以投sourcedynamic它传递给方法之前。这将导致在运行时解析正确的泛型重载,而无需任何难看的反射代码:

void Method(IEnumerable source)
{
    var enumerator = source.GetEnumerator();

    if (enumerator.MoveNext())
    {
        Method2((dynamic)source);
    }
}

As with Jon's second solution, this will only work if your source is actually an IEnumerable<T>. If it is a plain IEnumerablethen you'll need to create another method that converts it to the correct IEnumerable<T>type, as in the following solution:

与 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);
    }
}