通用扩展方法可以返回IEnumerable的类型吗?

时间:2015-08-21 11:45:16

标签: c# generics types extension-methods ienumerable

我想编写一个具有泛型参数的扩展。 让我用代码展示。

public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> value, int countOfEachPart) 
{
    //spliting value
}

此方法始终返回IEnumerable<IEnumerable<T>>但我想回复一些想法IEnumerable<TList<T>>

例如;
如果我通过了List<T>我应该返回IEnumerable<List<T>>如果我通过了T[]我应该返回IEnumerable<T>[]等等。

我试过这段代码,但我没能成功

public static IEnumerable<TList<T>> Split<TList,T>(this TList<T> value, int countOfEachPart) where TList:IEnumerable<T> //or where TList:IEnumerable
{
    //spliting value
}

有没有办法返回传递的IEnumerable类型?

3 个答案:

答案 0 :(得分:4)

因为你最有可能必须实现对数组和列表的支持,所以你必须编写重载方法。

public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> value, int countOfEachPart)     

public static IEnumerable<IList<T>> Split<T>(this IList<T> value, int countOfEachPart) 

public static IEnumerable<T[]> Split<T>(this T[] value, int countOfEachPart) 

关于方法的逻辑(实际上不是问题的一部分,但已经在你自己的答案中讨论过):我已经实现了一个类似的,只基于IEnumerables。它看起来像这样:

    public static IEnumerable<IEnumerable<T>> Page<T>(this IEnumerable<T> source, int pageSize)
    {
        T[] sourceArray = source.ToArray();
        int pageCounter = 0;
        while (true)
        {
            if (sourceArray.Length <= pageCounter * pageSize)
            {
                break;
            }
            yield return sourceArray
                .Skip(pageCounter * pageSize)
                .Take(pageSize);

            pageCounter++;
        }
    }

由于ToArray,我对它并不完全满意。我更喜欢一个解决方案,其中整个事情尽可能地懒惰,并且只在迭代结果时迭代源。这会有点复杂,我没有时间。但是,稍后可以通过更好的实现轻松取代它。

答案 1 :(得分:1)


我完成了我的扩展。
我使用了@Stefan Steinegger和@Luaan的答案。由于
这是我的延伸的最终代码。 我打开你的批评和建议

public static class Extension
    {
        private static IEnumerable<TList> Split<TList, T>(this TList value, int countOfEachPart) where TList : IEnumerable<T>
        {
            int cnt = value.Count() / countOfEachPart;
            List<IEnumerable<T>> result = new List<IEnumerable<T>>();
            for (int i = 0; i <= cnt; i++)
            {
                IEnumerable<T> newPart = value.Skip(i * countOfEachPart).Take(countOfEachPart).ToArray();
                if (newPart.Any())
                    result.Add(newPart);
                else
                    break;
            }

            return result.Cast<TList>();
        }

        public static IEnumerable<IDictionary<TKey, TValue>> Split<TKey, TValue>(this IDictionary<TKey, TValue> value, int countOfEachPart)
        {
            IEnumerable<Dictionary<TKey, TValue>> result = value.ToArray()
                                                                .Split(countOfEachPart)
                                                                .Select(p => p.ToDictionary(k => k.Key, v => v.Value));
            return result;
        }

        public static IEnumerable<IList<T>> Split<T>(this IList<T> value, int countOfEachPart)
        {
            return value.Split<IList<T>, T>(countOfEachPart);
        }

        public static IEnumerable<T[]> Split<T>(this T[] value, int countOfEachPart)
        {
            return value.Split<T[], T>(countOfEachPart);
        }

        public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> value, int countOfEachPart)
        {
            return value.Split<IEnumerable<T>, T>(countOfEachPart);
        }
    }

答案 2 :(得分:0)

TList是一个类型参数 - 它不是通用的。但它不一定是:

public static IEnumerable<TList> Split<TList,T>
  (this TList value, int countOfEachPart) 
  where TList: IEnumerable<T>

可悲的是,这并不允许对T ...

进行类型推断