Подтвердить что ты не робот

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

Ответ 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 });
    }
}