Search code examples
c#oopgenericsgeneric-programmingbogus

Returning a concrete implementation as a generic


I have an interface which looks like this:

public interface IFaker
{
    Faker<T> GetFaker<T>() where T : class;
}

public class DogFaker : IFaker
{
    public Faker<T> GetFaker<T>() where T : class
    {
        return new Faker<Dog>()
            .RuleFor(dog => dog.Name, f => f.Name.FirstName(Name.Gender.Male))
            .RuleFor(dog => dog.IsGoodBoy, f => f.Random.Bool());
    }
}

The problem is - I can't return a Faker<Dog> in place of Faker<T> e.g

Bogus.Faker<_scratchpad.models.Dog>' to 'Bogus.Faker<T>

Obviously I can't change new Faker<Dog> to new Faker<T> because then I can't access the Dog properties.

I want to use the object like so:

private Dictionary<string, object> _fakers;

public FakerService()
{
    _fakers = InitialiseFakers();
}

private Dictionary<string, object> InitialiseFakers()
{
   return new Dictionary<string, object>()
    {
        {typeof(Dog).FullName, new DogFaker().GetFaker<Dog>()}
    };
}

public IEnumerable<T> Generate<T>(int count) where T : class
{
    var faker = GetFaker<T>();
    return faker.Generate(count);
}

private Faker<T> GetFaker<T>() where T : class
{
    var faker = (Faker<T>)_fakers[typeof(T).FullName];
    return faker;
}

Solution

  • I would suggest starting with:

    public interface IFaker<T> where T : class
    {
        Faker<T> GetFaker();
    }
    
    public class DogFaker : IFaker<Dog>
    {
        public Faker<Dog> GetFaker() 
        {
            return new Faker<Dog>()
            // whatever else you need here
            ;
        }
    }
    

    This way DogFaker.GetFaker() has its T constraint defined explicitly as Dog - rather than it being defined by the caller.