通用重载方法解析问题

时间:2010-07-22 07:25:06

标签: c#

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

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;等等。

6 个答案:

答案 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;
    }

    ...
}