如何将通用参数转换为通用接口?
How to cast generic parameter to generic interface?
我想要一个扩展方法来打印 IEnumerable< X > 的所有内容
public static IEnumerable<T> log_elements<T>(this IEnumerable<T> collection, bool recursive = true)
{
Form1.log("[");
foreach (T i in collection)
if(recursive&&(i.GetType().GetGenericTypeDefinition()==typeof(IEnumerable<>)))
(IEnumerable<>)i.log_elements();//This doesn't work
else
Form1.log(i);
Form1.log("]");
return collection;
}
如果它包含 IEnumerable< Y >,也应该为其调用该方法。
我无法添加 log_elements<T>(this IEnumerable<IEnumerable<T>>,bool)
,因为 IEnumerable<T>
匹配原始方法的 T
。
我几乎可以肯定,在 c# 中应该有针对这种简单问题的解决方案。
编辑备注:
这不解决 IEnumerable,但省略了反射的需要。
此代码的主要目标是 'easy' 理解语法并尽可能重用。
如果你真的想要递归,下面的代码应该可以满足你的目的;它更可重用,因为它不依赖于方法范围之外的变量:
/// <summary>
/// Returns the top level items including all their recursive descendants.
/// </summary>
/// <typeparam name="T">The generic enumerable type parameter.</typeparam>
/// <param name="source">The source to traverse.</param>
/// <param name="childPropertyExpression">The recursive property expression.</param>
/// <returns>IEnumerable(<typeparamref name="T"/>)</returns>
public static IEnumerable<T> IncludeDescendants<T>(this IEnumerable<T> source, Expression<Func<T, IEnumerable<T>>> childPropertyExpression)
{
// The actual recursion is processed inside the private static method
// This method is serving the purpose of writing expressions.
var items = IncludeDescendants(source, childPropertyExpression.Compile());
foreach (var item in items)
{
yield return item;
}
}
private static IEnumerable<T> IncludeDescendants<T>(IEnumerable<T> source, Func<T, IEnumerable<T>> childPropertyFunc)
{
foreach (var item in source)
{
yield return item;
var subSource = childPropertyFunc.Invoke(item);
if (subSource != null)
{
foreach (var subItem in IncludeDescendants(subSource, childPropertyFunc))
{
yield return subItem;
}
}
}
}
用法:
var allChildrenRecursive = MyObject.Children.IncludeDescendants(c => c.Children);
foreach(var child in allChildrenRecursive)
{
Log(child);
}
在这种情况下,每个 child 都有一个相同类型 children 的递归集合。
当心循环引用,因为在这种情况下,这将达到您的堆栈允许的范围。 (WhosebugException).
var a = i as IEnumerable<T>;
(IEnumerable<T>) a.log_elements(true);
从 IEnumerable<T>
更改为非通用 IEnumerable
(通用版本无论如何都继承自它)。
public static IEnumerable<T> log_elements<T>(this IEnumerable<T> collection, bool recursive = true)
{
logElementsInternal(collection, recursive);
return collection;
}
private static void logElementsInternal(IEnumerable collection, bool recursive)
{
Form1.log("[");
foreach (var i in collection)
if(recursive && i is IEnumerable)
logElementsInternal((IEnumerable)i);
else
Form1.log(i);
Form1.log("]");
}
我想要一个扩展方法来打印 IEnumerable< X > 的所有内容
public static IEnumerable<T> log_elements<T>(this IEnumerable<T> collection, bool recursive = true)
{
Form1.log("[");
foreach (T i in collection)
if(recursive&&(i.GetType().GetGenericTypeDefinition()==typeof(IEnumerable<>)))
(IEnumerable<>)i.log_elements();//This doesn't work
else
Form1.log(i);
Form1.log("]");
return collection;
}
如果它包含 IEnumerable< Y >,也应该为其调用该方法。
我无法添加 log_elements<T>(this IEnumerable<IEnumerable<T>>,bool)
,因为 IEnumerable<T>
匹配原始方法的 T
。
我几乎可以肯定,在 c# 中应该有针对这种简单问题的解决方案。
编辑备注:
这不解决 IEnumerable,但省略了反射的需要。
此代码的主要目标是 'easy' 理解语法并尽可能重用。
如果你真的想要递归,下面的代码应该可以满足你的目的;它更可重用,因为它不依赖于方法范围之外的变量:
/// <summary>
/// Returns the top level items including all their recursive descendants.
/// </summary>
/// <typeparam name="T">The generic enumerable type parameter.</typeparam>
/// <param name="source">The source to traverse.</param>
/// <param name="childPropertyExpression">The recursive property expression.</param>
/// <returns>IEnumerable(<typeparamref name="T"/>)</returns>
public static IEnumerable<T> IncludeDescendants<T>(this IEnumerable<T> source, Expression<Func<T, IEnumerable<T>>> childPropertyExpression)
{
// The actual recursion is processed inside the private static method
// This method is serving the purpose of writing expressions.
var items = IncludeDescendants(source, childPropertyExpression.Compile());
foreach (var item in items)
{
yield return item;
}
}
private static IEnumerable<T> IncludeDescendants<T>(IEnumerable<T> source, Func<T, IEnumerable<T>> childPropertyFunc)
{
foreach (var item in source)
{
yield return item;
var subSource = childPropertyFunc.Invoke(item);
if (subSource != null)
{
foreach (var subItem in IncludeDescendants(subSource, childPropertyFunc))
{
yield return subItem;
}
}
}
}
用法:
var allChildrenRecursive = MyObject.Children.IncludeDescendants(c => c.Children);
foreach(var child in allChildrenRecursive)
{
Log(child);
}
在这种情况下,每个 child 都有一个相同类型 children 的递归集合。
当心循环引用,因为在这种情况下,这将达到您的堆栈允许的范围。 (WhosebugException).
var a = i as IEnumerable<T>;
(IEnumerable<T>) a.log_elements(true);
从 IEnumerable<T>
更改为非通用 IEnumerable
(通用版本无论如何都继承自它)。
public static IEnumerable<T> log_elements<T>(this IEnumerable<T> collection, bool recursive = true)
{
logElementsInternal(collection, recursive);
return collection;
}
private static void logElementsInternal(IEnumerable collection, bool recursive)
{
Form1.log("[");
foreach (var i in collection)
if(recursive && i is IEnumerable)
logElementsInternal((IEnumerable)i);
else
Form1.log(i);
Form1.log("]");
}