【问题标题】:Can I have a different Extension method for IEnumerable<T> than for <T>?我可以为 IEnumerable<T> 提供与 <T> 不同的扩展方法吗?
【发布时间】:2015-03-07 22:25:11
【问题描述】:

我有一个适用于任何类的扩展方法,但如果我正在处理IEnumerable&lt;T&gt;,我想调用一个特殊版本。

举例

public static class ExtensionMethods
{

    public static dynamic Test<T>(this T source)
    {   
        dynamic expandoObject = new System.Dynamic.ExpandoObject();
        var dictionary = (IDictionary<string,object>)expandoObject;

        dictionary["Test"] = source.ToString();

        return dictionary;
    }

    public static IEnumerable<dynamic> Test<T>(this List<T> source)
    {
        var result = new List<dynamic>();
        foreach(var r in source)
            yield return r.Test();          
    }


    public static IEnumerable<dynamic> Test<T>(this IEnumerable<T> source)
    {
        var result = new List<dynamic>();
        foreach(var r in source)
            yield return r.Test();          
    }
}   

// 用法

public class X 
{
    string guid = Guid.NewGuid().ToString();
}


void Main()
{
    List<X> list = new List<X>() { new X() };

    list.Test().Dump();                     // Correct but only works because there is an explicit overload for List<T>

    var array = list.ToArray();
    ((IEnumerable<X>) array).Test().Dump(); // Correct

     array.Test().Dump(); // Calls the wrong extension method
}

有什么方法可以让 array.Test() 调用 IEnumerable 版本而无需显式转换它?

或者,如果我为扩展方法指定不同的名称,如果我不小心使用了错误的方法,是否会出现编译器错误?

【问题讨论】:

  • 数组继承自 IEnumerable?
  • 你可以试试AsEnumerable(),但这只是转换为IEnumerable的最好和最短的方法:array.AsEnumerable().Test();
  • 数组实现了IEnumerable&lt;T&gt;,但该实现是在运行时添加的,这就是调用“错误”扩展方法的原因。

标签: c# extension-methods


【解决方案1】:

我认为您正试图以错误的方向解决它。 List 实现了 IEnumerable 接口,因此编译器可能无法解决将在 List 上调用的最佳方法的问题。你可以做什么——你可以测试 IEnumerable 是否是扩展方法中的一个列表。

public static IEnumerable<dynamic> Test<T>(this IEnumerable<T> source)
{
    if (source is List<T>) {
        // here 
    }
    var result = new List<dynamic>();
    foreach(var r in source)
        yield return r.Test();          
}

【讨论】:

  • 我不想要 List 和 IEnumerable 的不同版本。我刚刚添加了 List 版本,以表明如果我为 List 创建显式重载,它将被正确调用。如果我为 T[] 创建了显式重载,它将适用于数组,但我无法为实现 IEnumerable 的每个可能的类创建显式重载。
  • 对不起,我的意思是你可以测试源代码是否是一个数组if (sourse is T[])
  • 还是漏掉了没有调用IEnumerable扩展方法这一点。
【解决方案2】:

您可以指定T 而不是依赖类型推断,这将提示编译器使用正确的扩展方法。代码如下所示:

var array = list.ToArray();
array.Test<X>().Dump();

发生的情况是,编译器无法判断要使用哪个扩展,因为Array 是两个方法签名的有效参数:

public static dynamic Test<T>(this T source) { .. }

public static IEnumerable<dynamic> Test<T>(this IEnumerable<T> source) { .. }

在第一种情况下,编译器可以假设TArray 类型。因此,编译器必须选择一个(可能是首先定义的?)。

【讨论】:

  • 这可行,但它不会强制指定 T,因此仍会编译不正确的代码。
  • 你是对的,遗憾的是我不知道在这种情况下编译是否有可能实现编译时错误。但是您可以添加另一种扩展方法,如下面的答案所述。
【解决方案3】:

添加此扩展方法以显式捕获所有数组类型:

public static IEnumerable<dynamic> Test<T>(this T[] source)
{
    var result = new List<dynamic>();
    foreach(var r in source)
        yield return r.Test();          
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-28
    • 2011-11-06
    • 2015-10-22
    • 2016-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-02
    相关资源
    最近更新 更多