Should I use different return types on overloaded methods?
Are there any best practices on returning different return types on overloaded methods? For instance if I have a Load method in my DAL, I either want to load a single item or a bunch of items. I know that I could use a number of approaches:
Load one object
MyBusinessObject LoadOne(int id)
{
}
Load multiple objects
MyBusinessObject[] LoadMany(params int[] ids)
{
}
Now something I know I can do is to overload one method and have different return types. Like so:
MyBusinessObject Load(int id)
{
}
And
MyBusinessObject[] Load(params int[] ids)
{
}
While it seems there's nothing to stop me doing this, and it keeps things tidy from an API perspective, does this seem like a good idea? I came across it last night and part of me thinks I shouldn't be doing this for the reason of wanting matching return types for overloaded method.
I could also have the Load(int id) method return a collection that only holds one item. It seems to me that this violates the principle of least surprise though in that if you're expecting one item returned, you should return that item, you shouldn't return a list containing a single item.
So here are my conflicting thoughts sur开发者_如何学编程rounding these ideas:
- Overloaded methods should all return the same type.
- If methods do the same thing, don't give them a bunch of different names, overload the same method name. It makes things simpler from an API user's perspective, they don't have to trawl through a bunch of different methods that all essentially do the same thing but with different parameters.
- Return the most obvious type for the method, i.e. if the user is likely to be expecting a collection of items, return a collection of items, if they are likely to be expecting a single item, return a single item.
So the latter two thoughts kind of outweigh the first, but at the same time, the first thought seems like a programmatic best practice of sorts.
Are there any best practices surrounding this practice? I'd be interested to hear others' thoughts on the subject.
I might be tempted to make the API explicit and use plurality in the names:
Customer LoadCustomer(int id) {...}
Customer[] LoadCustomers(params int[] id) {...}
Actually, the params
is rarely useful here - you don't usually know the ids at compile-time.
You can just look to an existing APIs. Let's take LINQ for example, it has "Select" method that returns many entities and also "Single" method that returns only one entity. Most of the existing APIs has two different methods, not an overloaded ones and I think this is logical and more readable.
There are probably exceptions, but unless you have a really good reason to return different types, a function and its overloads should return the same type so that you don't drive other developers crazy.
For example:
var a = MyFunc("Some text");
and
var a = MyFunc(1);
both look like they should resolve the var to the same type to me. Before I deviated from having all overloads return the same type I would make sure I had a very solid reason for returning different types.
I tend to follow the first point in your list of "thoughts surronding this idea" that says "overloads should return the same type".
but you can then overload the "LoadMany" with some different scenarios;
public Customer Load(int id)
{
// return just one customer
}
public List<Customer> LoadMany()
{
// return every single customer
}
public List<Customer> LoadMany(int statusFilter)
{
// return a filtered list of customers
}
public List<Customer> LoadMany(DateTime InitialContactFrom)
{
// return a filtered list of customers
}
public List<Customer> LoadMany(DateTime InitialContactFrom, DateTime InitialContactBefore)
{
// return a filtered list of customers
}
...whatever combinations you need can obviously be added but in the end, LoadMany returns a list and Load returns one entity.
My personal idea is that the latter method seems more understandable from an API-user perspective.
精彩评论