C# 强制执行要调用的正确方法重载

C# 强制执行要调用的正确方法重载,c#,.net,generics,.net-core,overloading,C#,.net,Generics,.net Core,Overloading,我有两种具有以下签名的方法: public void DoSomething<T>(T value) { ... } public void DoSomething<T>(IEnumerable<T> value) { ... } 它仍然跳转到第一个。 我如何强制它将进入第二个方法?例如,对泛型参数使用where子句 编辑: 更准确地说:为什么它不起作用,即使我更具体,并将重载更改为类似的内容,这将导致在尝试调用上述方法时出现编译错误: public vo

我有两种具有以下签名的方法:

public void DoSomething<T>(T value) { ... }

public void DoSomething<T>(IEnumerable<T> value) { ... }
它仍然跳转到第一个。 我如何强制它将进入第二个方法?例如,对泛型参数使用where子句

编辑:

更准确地说:为什么它不起作用,即使我更具体,并将重载更改为类似的内容,这将导致在尝试调用上述方法时出现编译错误:

public void DoSomething<T>(T value) where T : IComparable { ... }

public void DoSomething<T>(IEnumerable<T> value) where T : IComparable { ... }
public void DoSomething(T值),其中T:i可比较{…}
公共void DoSomething(IEnumerable value),其中T:IComparable{…}

您可以在初始化后首先将其显式强制转换为
IEnumerable
引用,然后将其作为如下参数传递给方法,以便它解析为更具体的重载,即
IEnumerable
而不是
T

DoSomething(new[] { "Pizza", "Chicken", "Cheese" } as IEnumerable<string>);
因此它调用第一个重载,而不是第二个重载

另一种解决方案是自己显式指定泛型类型参数,而不是编译器来解析自身,如:

DoSomething<String>(foods);
DoSomething(食品);
请参考我刚刚创建的以下演示小提琴来解释它:

编辑: 正如一些人所建议的那样,最好将方法名称更改为足够明显的名称,以便人们能够理解它可以处理哪种类型,尽管我提到的解决方法是可行的


希望有帮助

因为
T
接受所有类型,并且
string[]
不是直接的
IEnumerable
。它是从它衍生出来的

DoSomething(new[] { "Pizza", "Chicken", "Cheese" }.AsEnumerable());

当一个方法有多个适用的重载时,有几个不同的因素用于确定哪一个“更好”。其中一个因素是每个参数与方法签名中的类型的“接近程度”
string[]
是一个
IEnumerable
,因此它在该参数槽中有效,但是
string[]
IEnumerable
更接近
string[]
(精确匹配是“接近”)所以第一个重载比第二个重载更接近

因此,如果您将第二个参数的编译时类型更改为完全
IEnumerable
,那么这两个重载在“接近度”范围上将完全相同。由于这是相同的,它继续到另一个“更好”的分界线,即非泛型方法比泛型方法“更好”,因此您最终调用了您想要的重载

至于如何将该表达式的编译时类型更改为
IEnumerable
,最方便的方法是
AsEnumerable

DoSomething(new[] { "Pizza", "Chicken", "Cheese" }.AsEnumerable());

正如@Servy的优秀答案所解释的,编译器将为重载方法选择最佳匹配类型

通过将泛型函数改为使用
对象
,可以使任何
IEnumerable
函数与该函数最匹配

public void DoSomething(object value) { ... }

public void DoSomething<T>(IEnumerable<T> value) { ... }
public void DoSomething(对象值){…}
公共void DoSomething(IEnumerable值){…}

我认为从理论上讲,向下转换
对象
可能会导致与通用方法相比的性能问题,但由于
DoSomething
不会返回
或采用另一个匹配类型的参数
t
,因此,
object
的使用仅限于
DoSomething
的主体,并且允许对
T

合法的所有使用,将第二个重命名为
DoSomethingToACollection
我已经考虑过了,但我仍然希望保持名称不变。我也不太明白,为什么它会被编译。在生活中,我们不可能总是拥有我们想要的一切。您的
T值
参数将捕获所有内容,因为所有内容都是
T
。您不希望两个不同的方法具有相同的名称,一个方法显式处理
IEnumerable
,另一个显式地处理
T
保存您自己的头痛,只需更改名称。您可以在调用该方法时显式地指定泛型类型
DoSomething
。您可以将第一个重载更改为接受
对象而不是泛型吗?
字符串[]
不是
IEnumerable
的确如此。如果不是,那么您的代码将无法编译。
typeof(object[]).GetInterfaces().Contains(typeof(IEnumerable))==true
@Jonathon Chase,这当然是真的。数组无论如何都实现了IEnumerable。虽然这确实有效,但OP最好还是更改方法名称以避免以后出现混淆。是的,您是对的,方法名称应该清楚它的用途或只是
DoSomething(new[]{“Pizza”})
是的@CamiloTerevinto更新post或只是
DoSomething(新[]{“披萨”})
DoSomething(new[] { "Pizza", "Chicken", "Cheese" }.AsEnumerable());
DoSomething(new[] { "Pizza", "Chicken", "Cheese" }.AsEnumerable());
public void DoSomething(object value) { ... }

public void DoSomething<T>(IEnumerable<T> value) { ... }