Home > Software design >  Dictionary with generics
Dictionary with generics

Time:01-31

I've got the following interfaces:

public interface IObjectFinder<T> where T : IObject
{
    Task<IObjectResults<T>> FindAsync(string name);
}

public interface IObject
{
    string Id { get; }
}

I'd like to initialize a dictionary with the following:

this.finders = new Dictionary<string, IObjectFinder<IObject>>();
finders.Add("Car", new CarFinder<Car>());
finders.Add("Truck", new TruckFinder<Truck>());

Then create a simple controller method:

public async Task<IActionResult>(string objectType, string searchTerm)
{
    if (!finders.TryGetValue(objectType, out var finder))
        return NotFound();

    var result = await finder.FindAsync(searchTerm);
    return Ok(result);
}

The problem is the IObjectFinder<IObject> type of dictionary. A CarFinder<Car> isn't an IObjectFinder<IObject>. Is there an objectively better way to handle this? I'd like to avoid using MorseCode.ITask and dynamic's to avoid muddying up the code even more. How would you handle something like this?

CodePudding user response:

After I thought some more, I think it's similar to how some generic interfaces (e.g. IEnumerator<T> and IEnumerator) are defined. We need to define some non-generic interfaces first:

public interface IObjectResults
{
}

public interface IObjectFinder
{
    Task<IObjectResults> FindAsync(string name);
}

The generic interfaces need inherit them, and benefit from the default interface methods feature, we can implement them in this place.

public interface IObjectResults<T> : IObjectResults where T : IObject
{
}

public interface IObjectFinder<T> : IObjectFinder where T : IObject
{
    new Task<IObjectResults<T>> FindAsync(string name);

    async Task<IObjectResults> IObjectFinder.FindAsync(string name)
        => await FindAsync(name);
}

Now it's able to replace IObjectFinder<IObject> with IObjectFinder in the dictionary.

this.finders = new Dictionary<string, IObjectFinder>();
finders.Add("Car", new CarFinder());

var result = await finder.FindAsync(searchTerm);
  • Related