通用扩展方法可以return类型的IEnumerable吗?
Generic extension method can return type of IEnumerable?
我想编写一个具有通用参数的扩展。
让我用代码展示一下。
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> value, int countOfEachPart)
{
//spliting value
}
这个方法总是returning IEnumerable<IEnumerable<T>>
但我想return那样想IEnumerable<TList<T>>
例如;
如果我通过了 List<T>
我应该 return IEnumerable<List<T>>
如果我通过了 T[]
我应该 return 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
}
有什么方法可以return传递IEnumerable类型吗?
TList
是一个类型参数——它不是通用的。但不一定是:
public static IEnumerable<TList> Split<TList,T>
(this TList value, int countOfEachPart)
where TList: IEnumerable<T>
遗憾的是,这不允许 T
...
的类型推断
因为您很可能无论如何都必须实现对数组和列表的支持,所以您必须编写重载方法。
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
。我更喜欢一个解决方案,其中整个事情尽可能惰性,并且只在迭代结果时迭代源。这会有点复杂,我没有时间。但是,以后可以很容易地用更好的实现替换它。
我完成了扩展。
我同时使用了@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);
}
}
我想编写一个具有通用参数的扩展。 让我用代码展示一下。
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> value, int countOfEachPart)
{
//spliting value
}
这个方法总是returning IEnumerable<IEnumerable<T>>
但我想return那样想IEnumerable<TList<T>>
例如;
如果我通过了 List<T>
我应该 return IEnumerable<List<T>>
如果我通过了 T[]
我应该 return 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
}
有什么方法可以return传递IEnumerable类型吗?
TList
是一个类型参数——它不是通用的。但不一定是:
public static IEnumerable<TList> Split<TList,T>
(this TList value, int countOfEachPart)
where TList: IEnumerable<T>
遗憾的是,这不允许 T
...
因为您很可能无论如何都必须实现对数组和列表的支持,所以您必须编写重载方法。
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
。我更喜欢一个解决方案,其中整个事情尽可能惰性,并且只在迭代结果时迭代源。这会有点复杂,我没有时间。但是,以后可以很容易地用更好的实现替换它。
我完成了扩展。
我同时使用了@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);
}
}