C# 我可以为IEnumerable使用不同的扩展方法吗<;T>;而不是<;T>;?

C# 我可以为IEnumerable使用不同的扩展方法吗<;T>;而不是<;T>;?,c#,extension-methods,C#,Extension Methods,我有一个可以在任何类上使用的扩展方法,但是如果我正在使用IEnumerable,我想调用一个特殊的版本 比如说 public static class ExtensionMethods { public static dynamic Test<T>(this T source) { dynamic expandoObject = new System.Dynamic.ExpandoObject(); var dictionary

我有一个可以在任何类上使用的扩展方法,但是如果我正在使用
IEnumerable
,我想调用一个特殊的版本

比如说

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();          
    }
}   
公共静态类扩展方法
{
公共静态动态测试(此T源)
{   
dynamic expandoObject=新系统.dynamic.expandoObject();
变量字典=(IDictionary)expandoObject;
dictionary[“Test”]=source.ToString();
返回字典;
}
公共静态IEnumerable测试(此列表源)
{
var result=新列表();
foreach(源中的var r)
收益率回归r.检验();
}
公共静态IEnumerable测试(此IEnumerable源)
{
var result=新列表();
foreach(源中的var r)
收益率回归r.检验();
}
}   
//用法

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
}
公共类X
{
字符串guid=guid.NewGuid().ToString();
}
void Main()
{
List List=new List(){new X()};
list.Test().Dump();//正确,但只起作用,因为list有显式重载
var array=list.ToArray();
((IEnumerable)数组).Test().Dump();//正确
array.Test().Dump();//调用了错误的扩展方法
}
有没有办法让array.Test()调用IEnumerable版本而不必显式强制转换它


或者,如果我给扩展方法起了不同的名字,如果我不小心使用了错误的方法,我是否有可能得到一个编译器错误?

我认为您试图以错误的方向解决它。列表实现IEnumerable接口,因此编译器在解决将在列表上调用的最佳方法时可能会遇到问题。您可以做的是——您可以测试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();          
}
公共静态IEnumerable测试(此IEnumerable源代码)
{
如果(来源是列表){
//这里
}
var result=新列表();
foreach(源中的var r)
收益率回归r.检验();
}

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

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

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

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

public static IEnumerable<dynamic> Test<T>(this T[] source)
{
    var result = new List<dynamic>();
    foreach(var r in source)
        yield return r.Test();          
}
公共静态IEnumerable测试(此T[]源代码)
{
var result=新列表();
foreach(源中的var r)
收益率回归r.检验();
}

array继承自IEnumerable?您可以尝试
AsEnumerable()
,但这只是转换为
IEnumerable
:数组.AsEnumerable().Test()的最佳且最短的方法数组实现
IEnumerable
,但实现是在运行时添加的,这就是为什么调用“错误”扩展方法的原因。可能是重复的,我不希望列表与IEnumerable的版本不同。我刚刚添加了列表版本,以表明如果我为列表创建显式重载,它将被正确调用。如果我为T[]创建了一个显式重载,它将适用于数组,但我不能为实现IEnumerable的每个可能的类创建一个显式重载。很抱歉,我的意思是,如果(sourse是T[]),您可以测试源代码是否为数组
If
仍然忽略了不调用IEnumerable扩展方法这一点。这是可行的,但它不会强制指定t,因此仍然会编译不正确的代码。您是正确的,很遗憾,我不知道在这种情况下编译是否可能出现编译时错误。但您可以添加另一个扩展方法,如下面的答案中所述。
public static IEnumerable<dynamic> Test<T>(this T[] source)
{
    var result = new List<dynamic>();
    foreach(var r in source)
        yield return r.Test();          
}