因为您只调用.ToString(),您实际上并不真正关心T 是什么,只要它实现IEnumerable 与否。以下是如何在没有反射的情况下执行此操作,并且只使用IEnumerable 而不是IEnumerable<T>,我为String.Join 执行我自己的逻辑,因为它可以更轻松地编写递归逻辑。
internal static class ExtensionMethods
{
public static String Join<T>(this IEnumerable<T> enumerable)
{
StringBuilder sb = new StringBuilder();
JoinInternal(enumerable, sb, true);
return sb.ToString();
}
private static bool JoinInternal(IEnumerable enumerable, StringBuilder sb, bool first)
{
foreach (var item in enumerable)
{
var castItem = item as IEnumerable;
if (castItem != null)
{
first = JoinInternal(castItem, sb, first);
}
else
{
if (!first)
{
sb.Append(",");
}
else
{
first = false;
}
sb.Append(item);
}
}
return first;
}
}
Here is a test program 我写了这表明它一切正常(它测试类、结构和 IEnumerables 3 层深)。
编辑:根据您的评论,这里是另一个将嵌套的 IEnumerables 展平的版本,您可以在完成后对每个元素执行任何操作。
internal static class ExtensionMethods
{
public static IEnumerable<T> SelectManyRecusive<T>(this IEnumerable enumerable)
{
foreach (var item in enumerable)
{
var castEnumerable = item as IEnumerable;
if (castEnumerable != null
&& ((typeof(T) != typeof(string)) || !(castEnumerable is string))) //Don't split string to char if string is our target
{
foreach (var inner in SelectManyRecusive<T>(castEnumerable))
{
yield return inner;
}
}
else
{
if (item is T)
{
yield return (T)item;
}
}
}
}
}
我还遇到了一个错误,我认为这可能会影响我回答的第一部分,string 在技术上是IEnumerable<char>,所以IEnumerable<string> 也可以被视为IEnumerable<IEnumerable<char>> 并且它可能会放入太多,。第二个版本对此进行了检查。
Test program 展示了如何使用此方法和String.Join 一起使用。