Search code examples
c#oopdependency-injectionabstract-classderived-class

Why is my implementation always calling the same derived class?


I have a base class that accepts a Type as a constructor argument, and two derived classes that inherit from that base class. I also have an interface of that base class, that I inject to use in other places.

When I call the base method "FormatValue", passing different types as parameters, I always get the same result (it call the method in one of the classes, ignoring my type parameter).

What am I doing wrong?

public interface IFormatService
{
    string FormatValue(object value);
}
public abstract class FormatService : IFormatService
{
    protected FormatService(Type type)
    { }

    public abstract string FormatValue(object value);
}

public static class Program
{
    private static void Main(string[] args)
    {
        var serviceProvider = new ServiceCollection()
            .AddSingleton<IFormatService, CurrencyFormat>()
            .AddSingleton<IFormatService, DateTimeFormat>()
            .BuildServiceProvider();

        var formatService = serviceProvider.GetService<IFormatService>();

        Console.WriteLine(formatService.FormatValue(DateTime.Now));
        Console.WriteLine(formatService.FormatValue(200));

        Console.ReadLine();
    }
}

public class CurrencyFormat : FormatService
{
    public CurrencyFormat() : base(typeof(decimal))
    {
    }

    public override string FormatValue(object value) => "CurrencyFormatter";
}

public class DateTimeFormat : FormatService
{
    public DateTimeFormat() : base(typeof(DateTime))
    {
    }

    public override string FormatValue(object value) => "DateTimeFormatter";
}

Current result:

DateTimeFormatter
DateTimeFormatter

Expected result:

DateTimeFormatter
CurrencyFormatter

Solution

  • If you want to call different methods depending on the type of parameter, there are many ways to do it.

    One way is by using the dynamic that choose the best overload at runtime:

    public interface IFormatService
    {
        string FormatValue(object value);
    }
    
    public class FormatService : IFormatService
    {
        public string FormatValue(object value)
        {
            dynamic valueAsDynamic = value;
    
            return FormatValueDynamic(valueAsDynamic);
        }
    
        string FormatValueDynamic(dynamic value) => FormatValuePrivate(value);
    
        string FormatValuePrivate(DateTime value) => "DateTimeFormatter";
    
        string FormatValuePrivate(decimal value) => "CurrencyFormatter";
    
        string FormatValuePrivate(object value) => throw new NotSupportedException();
    }
    

    This way you can add all the methods you need.