Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reducing constructor boiler plate code

Tags:

c#

I often end up writing classes like this:

public class Animal
{
    public string Colour { get; set; }
    public int Weight { get; set; }

    public Animal(Dog data)
    {
        this.Colour = data.Colour;
        this.Weight = data.Weight;
    }

    public Animal(Cat data)
    {
        this.Colour = data.Colour;
        this.Weight = data.Weight;
    }
}

When you have lots of properties and types then you quickly end up with a lot of boiler plate code. Ideally in this situation I would just create an IAnimal interface and reference that. I'm currently in a situation where the Dog and Cat classes exist in a third party assembly and I can't modify them. The only solution that I can come up with is:

public class Animal
{
    public string Colour { get; set; }
    public int Weight { get; set; }

    public Animal(Cat data){Init(data);}
    public Animal(Dog data){Init(data);}

    private void Init(dynamic data)
    {
        this.Colour = data.Colour;
        this.Weight = data.Weight;
    }
}

This works but I lose all type safety, is there a better solution than constructor injection?

Thanks,

Joe

EDIT: Here is a real world example. I have a third party library which returns 3 objects called:

  • GetPageByIdResult
  • GetPagesByParentIdResult
  • GetPagesByDateResult

(These are all auto generated classes from a service reference and the properties are pretty much identical)

Instead of dealing with these three objects I want to deal with a single PageData object or a collection of them.

like image 267
JoeS Avatar asked Aug 20 '15 12:08

JoeS


2 Answers

You can have the logic in one common constructor that all the other constructors call:

public class Animal
{
    public string Colour { get; set; }
    public int Weight { get; set; }

    public Animal(Dog data) : this (data.Colour, data.Weight)
    {
    }

    public Animal(Cat data) : this (data.Colour, data.Weight)
    {
    }

    private Animal(string colour, int weight)
    {
        this.Colour = colour;
        this.Weight = weight;
    }
}

This is pretty similar to your second solution but it doesn't lose type safety.

like image 176
James Brierley Avatar answered Sep 30 '22 11:09

James Brierley


I'm currently in a situation where the Dog and Cat classes exist in a third party assembly and I can't modify them

I'd suggest Automapper-based solution:

public static class AnimalFactory
{
    public static Animal Create<T>(T source)
        where T : class
    {
        Mapper.CreateMap<T, Animal>();
        return Mapper.Map<Animal>(source);
    }
}

Usage:

        var catAnimal = AnimalFactory.Create(cat);
        var dogAnimal = AnimalFactory.Create(dog);

Of course, you can provide a way to custom mapping configuration, if needed.

like image 26
Dennis Avatar answered Sep 30 '22 10:09

Dennis