如何将泛型参数转换为通用接口?

时间:2015-06-02 19:57:00

标签: c# generics casting extension-methods

我想要一个扩展方法来打印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&lt; Y&gt;,也应该调用该方法。

我无法添加log_elements<T>(this IEnumerable<IEnumerable<T>>,bool),因为IEnumerable<T>与原始方法的T匹配。

我几乎可以肯定,在c#中应该有这样一个简单问题的解决方案。

3 个答案:

答案 0 :(得分:2)

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("]"); } (通用版本无论如何继承)。

 (clientKampanj.VisaKampanj(vara.ProduktNamn) / 100)

答案 1 :(得分:1)

编辑备注:
这不涉及IEnumerable,但忽略了反射的需要。 这段代码的主要目标是“简单易行”。理解语法并尽可能重用。

如果您确实希望递归,则以下代码应满足您的目的;它更可重用,因为它不依赖于方法范围之外的变量:

/// <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);
}

在这种情况下,每个孩子都有一个相同类型孩子的递归集合 请注意循环引用,因为在这种情况下,这将达到您的堆栈允许的范围。 (StackOverflowException)。

答案 2 :(得分:-1)

var a = i as IEnumerable<T>;
(IEnumerable<T>) a.log_elements(true);