将静态扩展分辨率限制为最窄的匹配签名

问题描述 投票:0回答:1

[我有两个静态扩展方法类似,其中一个方法使用IEnumerable,而另一个方法仅使用T。它们每个都返回一个ExpandoObject,并且我有两个用于优化目的,因为我在每个方法中都使用了反射。

这是我的方法签名:

public static ExpandoObject DoSomething<TSource>(this TSource source, string somethingElse)

public static ExpandoObject DoSomething<TSource>(this IEnumerable<TSource> source, string somethingElse)

我先写了后者,然后写出了单元测试来验证它,它通过了。然后,我写了前一个扩展,现在我的IEnumerable单元测试失败了,因为它与TSource(作为List)匹配,而不是与IEnumerable签名匹配。

我原本希望它会选择最窄的扩展名进行匹配,但是尽管它显示为与Intellisense中任一签名的匹配项,但它始终会选择非IEnumerable实现(而且我无法确定一种替代该实现的方法选择)。

1)是否有任何方法可以迫使它选择较窄的匹配项,或者以其他方式选择我要使用的扩展名?2)另外,是否有任何方法可以保护传入的类型,以防止TSource实现接收任何IEnumerable类型?

编辑:进一步研究这个问题,我仍然对编译器如何选择要使用的适当扩展感到困惑。

如果我通知输出的类型而不是使用var,如下所示,它仍然会选择Object方法并仅返回单个ExpandoObject而不是其中的IEnumerable:

IEnumerable<MyObj> data = new List<MyObj>(); var results = results.DoSomething("");

这将正确映射到返回IEnumerable的扩展名,但是如果我执行以下操作:

var data = new List<MyObj>(); var results = results.DoSomething("");

编译器将改为选择基于对象的方法,并将返回单个ExpandoObject。

鉴于List实现了IEnumerable,为什么编译器会选择映射到一个对象来确定适当的扩展名而不是选择IEnumerable版本,除非我将输入变量明确地转换为IEnumerable?

那么问题3 –是什么通知编译器选择使用哪个?显然,如果是显式类型匹配,它将选择可用的最窄选项,但是即使存在更窄的匹配(例如,列表输入),为什么它也立即退回到最宽的方法?

c# extension-methods
1个回答
1
投票
对于这种情况,编译器推断哪个函数正确(列表仍然是一个对象)是没有意义的,因此它使用匹配所有情况的函数。

最简单的方法是使用一个可以处理两种情况的函数。

public static object DoSomething<TSource>(this TSource source, string somethingElse) { if (source is System.Collections.IEnumerable) { Console.WriteLine("List"); } else { Console.WriteLine("Instance"); } return null; }

© www.soinside.com 2019 - 2024. All rights reserved.