简体   繁体   中英

Would using optional parameters in a repository interface be considered bad design?

I have created two classes to externally control page number ( Page ) and ordering ( Order ) on a repository. The repository exposes IEnumerable<T> and not IQueryable<T> since I want the repository to have strong testability.

Say, for example, if I had the following repository:

interface IUserRepository
{
    public IEnumerable<User> GetAll();
}

If I want the caller to control the subset of the response, they would need to pass in the page/order. So first thought would be to add overloads:

interface IUserRepository
{
    IEnumerable<User> GetAll();
    IEnumerable<User> GetAllOrderedAndPaged(Order order, Page page);
}

The problem I find with this is that I have to create multiple overloads which I find to be pretty tedious.

What I'm thinking (but not sure) of doing is having Order and Page be optional parameters:

interface IUserRepository
{
    IEnumerable<User> GetAll(Order order = null, Page page = null);
}

This way the calling code can easily sort/page, but not play with the main query (which is what I'm trying to avoid by exposing IEnumerable<T> instead of IQueryable<T> ).

Does this seem like a good or bad design? I know that could be considered a bit subjective, but I'm trying to see if there is functionally wrong with this. The main key is that my repositories are testable and the caller can't play around/change the query too much. I figured that since sorting/ordering are a very common task for a returning set of data, why not incorporate them into the design of the repository interface. Again, when testing, I only care that the right set of data is returned, but the caller can say "Now, give me this page/ordered subset of the data".

I would caution against using optional parameters since the default values will be compiled into the caller. This means that if the default values ever change, any code that uses the original default values will need to be recompiled.

This could be a problem in your specific example if, in the future, you decided that null wasn't a valid value, changed the defaults, and started throwing a ArgumentNullException if null was passed in. Any code that uses your interface will have to recompiled or potentially start throwing ArgumentNullExceptions .

You can read a much better explanation of this here and here .

The key take-away from this: once you expose a default parameter value on a public method, you can never change it without recompiling all clients that depend on it. For library writers, this never means never ever .

I've decided to use both parameters as properties on the repository itself. Taking into consideration the fact that the default value will be compiled into the caller, but also the fact that writing these parameters on every method on every possible repository could be tedious.

For my style of programming with a lot of lambda's optional parameters are not well suitable.

C# 4.0 Features – Named & Optional Parameters – Uh, no thanks: http://blogs.ijw.co.nz/chris/index.php/2010/05/c-4-0-features-named-optional-parameters-uh-no-thanks/

As a better design I would use a tuple as parameter. Or named class that aggregate page and order with default fields values. Sorry it's of course subjective.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM