通用重载方法解析问题

我有两种使用这些签名的方法:

void Method(T data) { } void Method(IEnumerable data) { } 

它采用相同方法的重载来获取单个对象或它们的列表。 如果我尝试将List 传递给它,它会解析为第一种方法,当我想要第二种方法时。 我必须使用list.AsEnumerable()来解决它的问题。 无论列表是类型T [],IList ,List ,Collection ,IEnumerable 等,有没有办法让它解决到秒。

最好的解决方案:首先不要去那里 。 这是一个糟糕的设计 。 您会注意到没有一个框架类可以做到这一点。 列表有两种方法:Add和AddRange。 第一个添加一个项目,第二个添加一系列项目。

这是一个糟糕的设计,因为您正在编写一个自动生成错误的设备 。 再次考虑一个可变列表的例子:

 List myqueries = new List(); myqueries.Add(from c in customers select c.Name); myqueries.Add(from o in orders where o.Amount > 10000.00m select o); 

您希望在查询列表中添加两个查询; 如果Add重载以获取序列,那么这会将查询结果添加到列表中,而不是查询。 您需要能够区分查询及其结果 ; 它们在逻辑上完全不同。

最好的办法是使方法有两个不同的名称。

如果你对这个糟糕的设计感到害怕,那么当你这样做时会受到伤害,不要这样做 。 过载分辨率旨在找到最佳匹配 。 不要试图锤击过载分辨率,以便它做更糟糕的事情。 再次,这是令人困惑和容易出错的。 使用其他一些机制解决问题。 例如:

 static void Frob(IEnumerable ts) // not generic! { foreach(object t in ts) Frob(t); } static void Frob(T t) { if (t is IEnumerable) Frob((IEnumerable) t); else // otherwise, frob a single T. } 

现在无论用户给你什么 – 一个T数组,一个T列表数组,无论如何,你最终只会擦拭单个Ts。

但同样,这几乎肯定是一个坏主意 。 不要这样做。 具有不同语义的两种方法应该具有不同的名称

取决于你是否这样做:

 var list = new List(); Method>(list); // Will resolve to the first overload. 

要么:

 var list = new List(); Method(list); // Will resolve to the second overload. 

发生这种情况的原因是,编译器会选择最具体的方法,因此在使用通用Method(T data)的地方,它被编译为Method>(List data) ,这比IEnumerable更具体

重载决策将尝试找到最佳匹配过载。

IEnumerable重载的情况下,您确实需要显式转换或使用IEnumerable ,因为那样确实是最佳匹配。

否则,简单的generics重载将被视为更好的匹配。

有关更多详细信息,请阅读Eric Lippert的“重载决议”博客条目。

有一些方法可以采取单一事物或一组事物的重载是不寻常的,不是吗? 为什么不呢

 void MethodSingle(T data) { Method(new T[] { data }); } void Method(IEnumerable data) { } 

我建议,对编译器和阅读器都比较清楚。

问:

无论列表是类型T [],IList <'T>,List <'T>,Collection <'T>,IEnumerable <'T>等,有没有办法让它解决到秒。

T []不是列表而是数组,所以可能没有。

我不确定这会有所帮助,但您可以尝试创建一个有限制的方法

 public void Method (U date) where U : IList { /* ... */ } 

为什么不这样扩展方法:

 void Method(T data) { var enumerable = data as IEnumerable; if(enumerable != null) { Method(enumerable); return; } ... }