Skip to content
Carmel Eve By Carmel Eve Software Engineer I
Design patterns in C# - The Adapter Pattern

Hello again, in this post I'm continuing my series on design patterns in C#, this time focusing on the adaptor pattern!

The adapter pattern is useful when you want to use a class that does not fit the design of your existing solution. This is often the case when using legacy or external code. The adapter pattern allows you to define a wrapper which executes the desired behaviour, but exposes it through a method which your solution expects.

The Introduction to Rx.NET 2nd Edition (2024) Book, by Ian Griffiths & Lee Campbell, is now available to download for FREE.

As always, I think this will become clearer when we delve into our (dinosaur-based) example.

Adapter Pattern Example

So, today we've been transported to a post-meteor world...

And in this world, in the age of mammals, we have a ChildCreator that expects things to work in a certain way:

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns.Adapter
{
    public static class ChildCreator
    {
        public static IChild CreateChild(IMammal mammal)
        {
            return mammal.GiveBirth();
        }
    }
}
Programming C# 12 Book, by Ian Griffiths, published by O'Reilly Media, is now available to buy.

Where the IMammal interface looks like this:

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns.Adapter
{
    public interface IMammal
    {
        IChild GiveBirth();
    }
}

The GiveBirth method produces an IChild, which has a single method, Cry (which I'm pretty sure is the main functionality of a new born baby, right?).

namespace DesignPatterns.Adapter
{
    public interface IChild
    {
        void Cry();
    }
}

However, though the world has moved on, we have a few legacy Triceratops hanging around, that are just trying to get along in an unfamiliar place... Unfortunately a Triceratops works somewhat differently to the majority of mammals (being a reptile and all), possessing a single LayEgg method:

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns.Adapter
{
    public class Triceratops
    {
        public TriceratopsEgg LayEgg()
        {
            return new TriceratopsEgg();
        }
    }
}

The TriceratopsEgg produced by this method then has the ability to hatch into a TriceratopsChild:

namespace DesignPatterns.Adapter
{
    public class TriceratopsEgg
    {
        public IChild Hatch()
        {
            return new TriceratopsChild();
        }
    }
}

And here is where our adapter comes in. We need a way that our ChildCreator can work with the Triceratops to produce a child.

If we define a TriceratopsToMammalAdapter, which implements the IMammal class, and wraps an internal Triceratops:

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns.Adapter
{
    public class TriceratopsToMammalAdapter : IMammal
    {
        private readonly Triceratops triceratops;

        public TriceratopsToMammalAdapter(Triceratops triceratops)
        {
            this.triceratops = triceratops;
        }

        public IChild GiveBirth()
        {
            TriceratopsEgg egg = triceratops.LayEgg();

            IChild child = egg.Hatch();

            return child;
        }
    }
}

Then the GiveBirth method can call the LayEgg method of the internal Triceratops, and then Hatch that egg to produce an IChild. We then return the child, and the Triceratops is able to continue to function in the new mammalian landscape.

If we now use our TriceratopsToMammalAdapter and ChildCreator:

public static void AdapterExample()
{
    var triceratops = new Triceratops();
    var child = ChildCreator.CreateChild(new TriceratopsToMammalAdapter(triceratops));

    child.Cry();
}

We can produce a healthy, crying, TriceratopsChild, with the output: TRICERATOPS IS CRYING! (Granted, as the lack of modern triceratops indicates, this probably isn't a long term solution and eventually that legacy code will likely still need to be replaced...)

Thanks for reading! Here's a link to the GitHub repository which contains all the code for this blog series. And watch of for my next blog on design patterns in C#!

Carmel Eve

Software Engineer I

Carmel Eve

Carmel is a software engineer and LinkedIn Learning instructor. She worked at endjin from 2016 to 2021, focused on delivering cloud-first solutions to a variety of problems. These included highly performant serverless architectures, web applications, reporting and insight pipelines, and data analytics engines. After a three-year career break spent travelling around the world, she rejoined endjin in 2024.

Carmel has written many blog posts covering a huge range of topics, including deconstructing Rx operators, agile estimation and planning and mental well-being and managing remote working.

Carmel has released two courses on LinkedIn Learning - one on the Az-204 exam (developing solutions for Microsoft Azure) and one on Azure Data Lake. She has also spoken at NDC, APISpecs, and SQLBits, covering a range of topics from reactive big-data processing to secure Azure architectures.

She is passionate about diversity and inclusivity in tech. She spent two years as a STEM ambassador in her local community and taking part in a local mentorship scheme. Through this work she hopes to be a part of positive change in the industry.

Carmel won "Apprentice Engineer of the Year" at the Computing Rising Star Awards 2019.