Reputation: 113
I want to write an extention which have generic parameters. Let me show with code.
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> value, int countOfEachPart)
{
//spliting value
}
This method is always returning IEnumerable<IEnumerable<T>>
But i want to return somethink like that IEnumerable<TList<T>>
For example;
if i passed List<T>
i should return IEnumerable<List<T>>
if i passed T[]
i should return IEnumerable<T>[]
etc.
I tried this code but i couldn't success
public static IEnumerable<TList<T>> Split<TList,T>(this TList<T> value, int countOfEachPart) where TList:IEnumerable<T> //or where TList:IEnumerable
{
//spliting value
}
Is there any way to return passed IEnumerable type?
Upvotes: 2
Views: 465
Reputation: 64628
Because you most probably have to implement support for arrays and lists anyway, you have to write overloaded methods.
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)
About the logic of the method (which is actually not part of the question, but had been discussed in your own answer): I've implemented a similar one, only based on IEnumerables. It looks like this:
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++;
}
}
I'm not entirely happy with it, because of the ToArray
. I would have preferred a solution where the whole thing is as lazy as possible and only iterates the source when iterating the result. It would be a bit more complicated and I didn't have the time. However, it can easily replaced by a better implementation later.
Upvotes: 4
Reputation: 113
i finished my extension.
I used both of @Stefan Steinegger and @Luaan answers. Thanks
This is final code of my extention.
I'm open your critics and suggestion
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);
}
}
Upvotes: 1
Reputation: 63732
TList
is a type argument - it isn't generic. But it doesn't have to be:
public static IEnumerable<TList> Split<TList,T>
(this TList value, int countOfEachPart)
where TList: IEnumerable<T>
Sadly, this doesn't allow type inference of T
...
Upvotes: 0