Generic List property wrapping

Putting a generic List property behind a class to created cleaner code

Home DailyDrop

Daily Knowledge Drop

When a class has a generic list property, a good idea is to put it behind a class to encapsulate all the functionality specific to the list in a single place, creating cleaner, more maintainable code.


Non-clean version

Non-clean is not entirely accurate, as there is nothing inherently wrong with this approach, its just not as clean as the class-wrapped version detailed in the next section.

In this example we have a Album class, which contains a list of Song titles:

public class Album
{
    public string Artist { get; set; }

    public List<string> Songs { get; set; }

    public int ReleaseYear { get; set; }
}

Suppose throughout the code we are required to get the top 5 songs in the list (perhaps to display in a summary on various screens within the application).


LINQ everywhere

One option is to perform the LINQ query to get the top 5 songs whenever it is required:

// This LINQ will be used every time the top 5 is required
IEnumerable<string>? top5Songs = album.Songs.OrderBy(s => s).Take(5);

This will work, but leads to duplication of code, and is difficult to maintain.

Helper method

Another option it to add a method into a helper class, or even into the Album class

public class Album
{
    public string Artist { get; set; }

    public List<string> Songs { get; set; }

    public int ReleaseYear { get; set; }

    public IEnumerable<string> GetTop5Songs()
    {
        return Songs.OrderBy(s => s).Take(5);
    }
}

Again, this will work and solves the code duplication issue. However the helper class, or Album class might end up containing numerous methods for numerous properties and ends up containing a wide range of functionality not directly related to it.


Clean version

Class wrapper

Another cleaner option, is to wrap the generic list in its own class, which can then hold all the methods related to the list:

// inherit from List
public class Songs : List<string>
{
    public IEnumerable<string> GetTop5Songs()
    {
        return this.OrderBy(s => s).Take(5);
    }

    // other methods related to Songs
}

The wrapper class inherits from List so automatically gets all the same functionality which was available when using List<string> explicitly.

The Album class will then use the Songs class, instead of List<String> to represent the songs of an album:

public class Album
{
    public string Artist { get; set; }

    public Songs Songs { get; set; }

    public int ReleaseYear { get; set; }
}

The relevent methods are now available on the property themselves:

var top5Songs = album.Songs.GetTop5Songs();

Cleaner, more maintainable and easier to find!


Notes

This is a relatively small change in code structure, but can definitely make a difference in the readability and maintainability of the code, bring related methods together in one place. Easier for a developer to find when using them, as well as when required to make changes to them!


References

Raw Coding-put generics behind classes

Daily Drop 192: 01-11-2022

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net array jagged