简体   繁体   中英

C# property of type IEnumerable

I have a little utility class called ContainerQuery which consists of zero or more ContainerQueryClause objects. After the user has prepared the query (ie added some clauses), the interface for my framework needs to get an object that supports:

interface IContainerQuery
{
    public IEnumerable<ContainerQueryClause> Clauses { get; }
}

What's the best implementation for IContainerQuery and why?

Option a)

class ContainerQuery
{
   public IEnumerable<ContainerQueryClause> Clauses { get; set; }
}

Option b)

class ContainerQuery
{
    public ContainerQuery()
    {
        Clauses = new List<ContainerQueryClause>();
    }

    public ICollection<ContainerQueryClause> Clauses { get; private set; }
}

Option c)

class ContainerQuery
{
    public ContainerQuery(IEnumerable<ContainerQueryClause> clauses)
    {
        Clauses = clauses;
    }

    public IEnumerable<ContainerQueryClause> Clauses { get; private set; }
}

Option d)

A combination of the above approaches or a completely different approach.

Side note 1: although ContainerQuery currently looks like " it is an enumerable of clauses" I want to model it for the future's sake as " has an enumerable of clauses".

Q: Is there a general best pracitce / pattern to create properties of type IEnumerable<T> ? If not, which approach fits which situations?

Side question: Would you create the interface IContainerQuery to have your internal framework use the immutable version only or would you forbear from doing so as "your internal code is not stupid enough to change the query later on"?


Some additional context: the user instantiates a new container query and wants to add some clauses. There is no funky fluent interface or things like that. After passing the finished query to my framework, my framework only wants to read all the clauses and is not allowed to make any changes to it (per interface description).

Start with the following implementation. Why? It provides minimum knowledge and possibilities to the caller.

  • you can use the class with the default constructor => no thinking needed about what happens to the parameter
  • Clauses is always initialized => no need to check for null
  • Clauses is IEnumerable => minimum set of functionality, maximum flexibility for inner representation

If you can live with the implementation, you are done. If you think that a ContainerQuery without Clause doesn`t make sense, add it to the constructor so that the caller is forced to give a value. If you suggest that the caller need some methods from ICollection (adding/removing after construction of ContainerQuery) than use this interface. And so on ...

public class ContainerQuery : IContainerQuery
{
  public ContainerQuery()
  {
    Clauses = new List<ContainerQueryClause>();
  }

  public IEnumerable<ContainerQueryClause> Clauses { get; private set; }
}

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