简体   繁体   中英

Generics, Factories and Returning More Derived Types

I'm playing with a sort of mishmash of factory, decorator and chain of responsibility. Essentially, I'm building a factory that receives a request object, analyzes it, and passes it further down the chain to a more specific inner factory. I've arrived at the structure below, but it has problems.

public abstract class AbstractFactoryRequest { }

public class SpecificFactoryRequest : AbstractFactoryRequest { }

public class MoreSpecificFactoryRequest : SpecificFactoryRequest { }

public interface IThing { }

public interface IThingFactory<in T> where T : AbstractFactoryRequest
{
    IThing GetThing(T request);
}

public abstract class AbstractThingFactory<T> : IThingFactory<T> where T : AbstractFactoryRequest
{
    public IThing GetThing(T request)
    {
        var innerFactory = GetInnerFactory(request);

        return innerFactory.GetThing(request);
    }

    protected abstract IThingFactory<T> GetInnerFactory(T request);
}

public class SpecificThingFactory : AbstractThingFactory<SpecificFactoryRequest>
{
    protected override IThingFactory<SpecificFactoryRequest> GetInnerFactory(SpecificFactoryRequest request)
    {
        return (IThingFactory<SpecificFactoryRequest>)new MoreSpecificThingFactory();
    }
}

public class MoreSpecificThingFactory : AbstractThingFactory<MoreSpecificFactoryRequest>
{
    protected override IThingFactory<MoreSpecificFactoryRequest> GetInnerFactory(MoreSpecificFactoryRequest request)
    {
        // return an even more specific factory...
    }
}

The problem occurs when trying to return the new'd up MoreSpecificThingFactory from within the SpecificThingFactory . With it casted as above, ReSharper calls this a suspicious cast, and without the cast, the compiler says there's no implicit conversion between MoreSpecificThingFactory and IThingFactory. I had thought perhaps this would work since the inheritance is there. Is there a way to fix this?

You get this error because you declare parameter as contravariant, which means that you can use only as a type of method arguments and not as a return type of interface methods. Here is an article about variance in generic types.

Now think about what you're trying to do. If you cast to less specific type, that would mean that you would be able to pass less specific parameter to method which accepts only more specific parameter and you obviously can't do that.

To make this cast work you should define MoreSpecificThingFactory as follows:

public class MoreSpecificThingFactory : AbstractThingFactory<SpecificFactoryRequest>
{
    protected override IThingFactory<SpecificFactoryRequest> GetInnerFactory(SpecificFactoryRequestrequest)
    {
        if (request is MoreSpecificFactoryRequest)
        {
            // return an even more specific factory...
        }
        // throw an exception or do something else
    }
}

EDIT:

It seems that you need to apply chain of responsibility pattern here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM