我有两种使用这些签名的方法:
void Method<T>(T data)
{
}
void Method<T>(IEnumerable<T> data)
{
}
它采用相同方法的重载来获取单个对象或它们的列表。如果我尝试传递List&lt;'T&gt;对它来说,它解析为第一种方法,当我想要第二种方法时。我必须使用list.AsEnumerable()来解析它到第二个。有没有办法让它解决到第二个,无论列表是类型T [],IList&lt;'T&gt;,列表&lt;'T&gt;,收集&lt;'T&gt;,IEnumerable&lt;'T&gt;等等。
答案 0 :(得分:10)
最佳解决方案:首先不要去那里。这是糟糕的设计。您会注意到没有任何框架类可以做到这一点。列表有两种方法:Add和AddRange。第一个添加单个项目,第二个添加一系列项目。
这是一个糟糕的设计,因为你正在编写一个自动生成错误的设备。再次考虑一个可变列表的例子:
List<object> myqueries = new List<object>();
myqueries.Add(from c in customers select c.Name);
myqueries.Add(from o in orders where o.Amount > 10000.00m select o);
您希望在查询列表中添加两个查询;如果Add重载以获取序列,则这会将查询结果添加到列表中,而不是查询。您需要能够区分查询及其< EM>结果;它们在逻辑上完全不同。
最好的办法是让方法有两个不同的名称。
如果你对这个糟糕的设计很感兴趣,那么如果你这样做会伤害,那就不要那样做了。过载分辨率旨在找到最佳匹配。不要试图锤击过载分辨率,以便它做一些更糟糕。再次,这是令人困惑和容易出错的。 使用其他一些机制解决问题。例如:
static void Frob(IEnumerable ts) // not generic!
{
foreach(object t in ts) Frob<object>(t);
}
static void Frob<T>(T t)
{
if (t is IEnumerable)
Frob((IEnumerable) t);
else
// otherwise, frob a single T.
}
现在无论用户给你什么 - 一个T的数组,一个T的列表数组,无论如何,你最终只会擦拭单个Ts。
但同样,这几乎肯定是一个坏主意。不要这样做。具有不同语义的两种方法应该具有不同的名称。
答案 1 :(得分:1)
取决于你是否这样做:
var list = new List<Something>();
Method<List<Something>>(list); // Will resolve to the first overload.
或者:
var list = new List<Something>();
Method<Something>(list); // Will resolve to the second overload.
发生这种情况的原因是,编译器会选择最具体的方法,因此在使用通用Method<T>(T data)
的地方,它被编译为Method<List<Something>>(List<Something> data)
,它比{{1}更具体。 }}
答案 2 :(得分:1)
重载决策将尝试找到最佳匹配过载。
如果IEnumerable<T>
重载,您确实需要显式转换或使用IEnumerable<T>
,因为这确实是最佳匹配。
否则,简单的泛型重载将被视为更好的匹配。
有关详细信息,请阅读Eric Lippert的"overload resolution"博客条目。
答案 3 :(得分:0)
有一个方法可以采取单一事物或一组事物的重载是不寻常的,不是吗?为什么不拥有
void MethodSingle<T>(T data)
{
Method(new T[] { data });
}
void Method<T>(IEnumerable<T> data)
{
}
我建议,编译器和阅读器都清楚。
答案 4 :(得分:0)
问:
有没有办法让它解决到第二个,无论列表是类型T [],IList&lt;'T&gt;,List&lt;'T&gt;,Collection&lt;'T&gt;,IEnumerable&lt;'T&gt;等等
T []不是列表而是数组,所以可能没有。
我不确定这会有所帮助,但您可以尝试创建一个带限制的方法
public void Method<U,T> (U date) where U : IList<T> { /* ... */ }
答案 5 :(得分:-1)
为什么不以这种方式扩展方法:
void Method<T>(T data)
{
var enumerable = data as IEnumerable<T>;
if(enumerable != null)
{
Method(enumerable);
return;
}
...
}