Got some vegetables going on:
public interface IVegetable
{
}
public class Potato : IVegetable
{
}
public class Onion : IVegetable
{
}
We'd focus on the onion and process it: I have single generic interface for a generic vegetable processor and one onion-specific:
public interface IVegetableProcessor<T> where T : IVegetable
{
string GetColor(T vegetable);
}
public interface IOnionProcessor : IVegetableProcessor<Onion>
{
void MakeCry(Onion onion);
}
public class OnionProcessor : IOnionProcessor
{
public string GetColor(Onion onion)
{
return "Purple";
}
public void MakeCry(Onion onion)
{
Console.WriteLine($"{onion} made you cry!");
}
}
As well as a generic factory:
interface IVegetableProcessorFactory
{
IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable;
}
internal class VegetableProcessorFactory : IVegetableProcessorFactory
{
public IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable
{
object processor = vegetable switch
{
Onion => new OnionProcessor(),
_ => throw new NotImplementedException($"Other vegetables not here yet")
};
return (IVegetableProcessor<T>)processor; //this will fail later
}
}
And finally this does not work:
static void Main(string[] args)
{
var onion = new Onion() as IVegetable;
var factory = new VegetableProcessorFactory();
var processor = factory.GetVegetableProcessor(onion);
Console.WriteLine(processor.GetColor(onion));
Console.ReadLine();
}
The error is:
System.InvalidCastException: 'Unable to cast object of type 'OnionProcessor' to type 'IVegetableProcessor`1[Vegetables.Program+IVegetable]'.'
How to make it understand the underlying class of IVegetable and cast the processor to it's corresponding type?
The fact that you have to cast in the first place is your hint that something is broken in your composition. As Selvin mentioned in the comments, implementing
IVegetableProcessor<Onion>is NOT the same thing as implementingIVegetableProcessor<IVegetable>.Your processor interfaces should implement
IVegetableProcessor<IVegetable>and take IVegetable instances, allowing contravariance for the input parameters:This correctly outputs "Purple" when run via: