Some context: I'd like to write a class where the main method for adding things to a collection is through a method (or methods) that are named Add (or something like that). And so the signature that seems best is params object[]. Internally, this very function would have to switch/if-else all the types that it can accept. So, initially it could accept this object[] array, but I might like to see it also accept object[][], and object[][][], etc, and then the method/function could flatten internally, so the user wouldn't need to do that prior to calling this function.
So...
Is it possible to write a function that can accept various Levels of List types for a single kind of object? As a side question, when designing an interface to a class, which is better to accept object[] or IEnumerable<object> or params object[]? (Edit: struck from the question because there is already enough going on.)
For instance, I'm thinking of a function that accepts both/all of object[], IEumerable<object>, and possibly further nesting like: IEnumerable<IEnumerable<object>>, object[][] (and on, on and on, etc).
您会注意到 List 类本身具有接受 T 的方法 Add 和接受 T 序列的 AddRange 方法。我们不会尝试重载 Add 来执行这两项操作,原因有两个。首先,因为添加一个东西和添加一堆东西在逻辑上是不同的,其次,因为它使重载解析变得非常复杂。
如果您想要一个采用 T 序列的方法,那么编写一个采用 T 序列的方法。如果调用者有一个序列序列,请让他们将其展平;不要试图代表他们猜测如何有效地做到这一点。
哪个更好:接受 object[] 或 IEnumerable
我们究竟应该如何知道?我们不是调用该方法的人。您应该询问的人是要编写代码来调用您的方法的人。
You'll notice that the List<T> class itself has methods Add that takes a T and AddRange that takes a sequence of T. We do not attempt to overload Add to do both, for two reasons. First, because adding a thing and adding a bunch of things are logically different, and second, because it greatly complicates overload resolution.
If you want a method that takes a sequence of T, then write a method that takes a sequence of T. If the caller has a sequence of sequences, make them flatten it; don't try to guess on their behalf how to do so effectively.
which is better: to accept object[] or IEnumerable<object> or params object[]?
How on earth should we know? We're not the ones calling the method. The person you should be asking is the person who is going to be writing code to call your method.
DoWork(params object[] args)
{
//do the actual work
}
DoWork(IEnumerable<object> args)
{
DoWork(args.ToArray());
}
//etc etc
One option is just to make one function and then overload it however many times you need. You can make the overloaded functions call the "base" function.
DoWork(params object[] args)
{
//do the actual work
}
DoWork(IEnumerable<object> args)
{
DoWork(args.ToArray());
}
//etc etc
It depends really on what you mean by list types. If you mean it explicitly, then you could have a method that accepts IList<T>. If you'd like to throw arrays into the mix, then you should really be accepting IEnumerable<T>. Unless you need to modify it, in which case arrays won't really work, so you could accept ICollection<T>.
Make two overloads of one function, one that accepts IEnumerable<T>, and one that accepts params T[]. Implement the latter by calling the former. Forget the nesting, LINQ can flatten collections easily using SelectMany.
发布评论
评论(4)
您会注意到
List
类本身具有接受 T 的方法 Add 和接受 T 序列的 AddRange 方法。我们不会尝试重载 Add 来执行这两项操作,原因有两个。首先,因为添加一个东西和添加一堆东西在逻辑上是不同的,其次,因为它使重载解析变得非常复杂。如果您想要一个采用 T 序列的方法,那么编写一个采用 T 序列的方法。如果调用者有一个序列序列,请让他们将其展平;不要试图代表他们猜测如何有效地做到这一点。
我们究竟应该如何知道?我们不是调用该方法的人。您应该询问的人是要编写代码来调用您的方法的人。
You'll notice that the
List<T>
class itself has methods Add that takes a T and AddRange that takes a sequence of T. We do not attempt to overload Add to do both, for two reasons. First, because adding a thing and adding a bunch of things are logically different, and second, because it greatly complicates overload resolution.If you want a method that takes a sequence of T, then write a method that takes a sequence of T. If the caller has a sequence of sequences, make them flatten it; don't try to guess on their behalf how to do so effectively.
How on earth should we know? We're not the ones calling the method. The person you should be asking is the person who is going to be writing code to call your method.
一种选择是只创建一个函数,然后根据需要多次重载它。您可以使重载函数调用“基”函数。
One option is just to make one function and then overload it however many times you need. You can make the overloaded functions call the "base" function.
这实际上取决于您所说的列表类型的含义。如果你的意思是明确的,那么你可以有一个接受
IList
。如果您想将数组放入其中,那么您确实应该接受IEnumerable
。除非您需要修改它,否则数组将无法真正工作,因此您可以接受ICollection
。It depends really on what you mean by list types. If you mean it explicitly, then you could have a method that accepts
IList<T>
. If you'd like to throw arrays into the mix, then you should really be acceptingIEnumerable<T>
. Unless you need to modify it, in which case arrays won't really work, so you could acceptICollection<T>
.对一个函数进行两次重载,一个接受
IEnumerable
,另一个接受params T[]
。通过调用前者来实现后者。忘记嵌套,LINQ 可以使用轻松展平集合选择许多
。Make two overloads of one function, one that accepts
IEnumerable<T>
, and one that acceptsparams T[]
. Implement the latter by calling the former. Forget the nesting, LINQ can flatten collections easily usingSelectMany
.