强制调用正确的方法重载

Seb*_*ull 0 .net c# generics overloading .net-core

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

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

public void DoSomething<T>(IEnumerable<T> value) { ... }
Run Code Online (Sandbox Code Playgroud)

我试着像这样打电话给第二个:

DoSomething(new[] { "Pizza", "Chicken", "Cheese" });
Run Code Online (Sandbox Code Playgroud)

它仍然跳进了第一个.如何强制它将进入第二种方法呢?例如,通过对通用参数使用where子句?

编辑:

更确切地说:为什么它不起作用,即使我更具体并将重载更改为类似的东西,这将在尝试调用上面显示的方法时导致编译错误:

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

public void DoSomething<T>(IEnumerable<T> value) where T : IComparable { ... }
Run Code Online (Sandbox Code Playgroud)

Ehs*_*jad 6

您可以IEnumberable<T>在初始化后将其显式地转换为引用,然后作为参数传递给方法,如下所示,以便它解析为更具体的重载,而IEnumerable<T>不是T:

DoSomething(new[] { "Pizza", "Chicken", "Cheese" } as IEnumerable<string>);
Run Code Online (Sandbox Code Playgroud)

或者也可以这样做:

IEnumerable<string> foods = new[] { "Pizza", "Chicken", "Cheese" };
DoSomething(foods);
Run Code Online (Sandbox Code Playgroud)

问题是当你没有把它强制转换时IEnumerable<T>,它在编译时的类型是String[],所以它将解析T为输入参数的重载.

所以在调用时,你的代码实际上是编译的:

DoSomething<String[]>(foods);
Run Code Online (Sandbox Code Playgroud)

所以它调用第一个重载而不是第二个重载.

另一个解决方案是自己明确指定泛型类型参数而不是编译器来解析自己,如:

DoSomething<String>(foods);
Run Code Online (Sandbox Code Playgroud)

请参阅我刚刚创建的以下演示小提琴来解释它:

演示小提琴

编辑:

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

希望能帮助到你!


Ser*_*rvy 5

当方法存在多个适用的重载时,有几个不同的因素用于确定哪个是"更好".其中一个因素是每个参数如何"关闭"到方法签名中的类型. string[]是一个IEnumerable<string>,所以它的有效实现该参数时隙,但string[]更接近string[](完全匹配是作为"接近",因为它得到)比它要IEnumerable<string>,所以第一个过载比第二"更接近".

因此,如果您将第二个参数的编译时类型更改为精确IEnumerable,那么两个重载在"紧密度"范围内将完全相同.由于它是相同的,它继续到另一个"更好"的决胜局,这是非泛型方法比通用方法"更好",所以你最终调用你想要的重载.

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

DoSomething(new[] { "Pizza", "Chicken", "Cheese" }.AsEnumerable());
Run Code Online (Sandbox Code Playgroud)

  • 或者只是`DoSomething <string>(new [] {"Pizza"})` (2认同)