Search code examples
c#.netclr

Factory pattern from generic interface


I have generic interface IProcessor<T, TU> and 2 implementations of it:

StandartDocumentProcessor and ModDocuemntProcessor.

I'm going to use Factory pattern (or smth similiar) to instantiate variable currentProcessor.

IProcessor<T, TU> currentProcessor = Factory.Create(argument).

Then I'm going to call method currentProcessor.ProcessFrom() and currentProcessor.ProcessTo().

1st problem: it's impossible to have IProcessor<T,TU> or IProcessor types for currentProcessor, as CLR doesn't allow this and insists to have specific type for my variable.

2nd problem: I surfed over the internet and found ugly solutions with Reflection or Activator.CreateInstance() which have familiar issues with downgrading performance.

Please advice, is it possible to avoid: reflection, casting to object or using dynamic.

UPD: IProcessor.cs

public interface IProcessor<T, TU> where T : DocumentValidation
    {
        HtmlContent RetrieveDocument(SearchItem item);

        bool ValidateObject(T obj);

        T ProcessFrom(HtmlContent content);

        TU ProcessTo(T source);

        bool SaveTo(TU target, T source);

    } 

First implementation of IProcessor - StandardDocumentProcessor.cs

class StandardDocumentProcessor : IProcessor<Document, XmlDocument>
    {
        public HtmlContent RetrieveDocument(SearchItem item)
        {
            throw new NotImplementedException();
        }

        public bool ValidateObject(Document obj)
        {
            throw new NotImplementedException();
        }

        public Document ProcessFrom(HtmlContent content)
        {
            throw new NotImplementedException();
        }

        public XmlDocument ProcessTo(Document source)
        {
            throw new NotImplementedException();
        }

        public bool SaveTo(XmlDocument target, Document source)
        {
            throw new NotImplementedException();
        }
    }

Second implementation of IProcessor - ModDocumentProcessor.cs

public class ModDocumentProcessor : IProcessor<ModDocument, XmlDocument>
    {
        public HtmlContent RetrieveDocument(SearchItem item)
        {
            throw new NotImplementedException();
        }

        public bool ValidateObject(ModDocument obj)
        {
            throw new NotImplementedException();
        }

        public ModDocument ProcessFrom(HtmlContent content)
        {
            throw new NotImplementedException();
        }

        public XmlDocument ProcessTo(ModDocument source)
        {
            throw new NotImplementedException();
        }

        public bool SaveTo(XmlDocument target, ModDocument source)
        {
            throw new NotImplementedException();
        }
    }

and now I'm going to create factory pattern to instantiate IProcessor<T, TU> with some specific class.

????? currentProcessor = Factory.Create(input_argument_which_allows_to_define_concrete_implementation_of_IProcessor)

That's no matter to display realization of Create method here. I'm kindly asking about just returning type of Create method.


Solution

  • Since C# 4.0 you can simple declare your factory method as dynamic and it will work:

    public static dynamic Create(string at) {
       if (condition)
         return new StandardDocumentProcessor();
       else
         return new ModDocumentProcessor();
    }
    

    Invocation:

    dynamic m = Create("mod");
    

    Of course, this is like cheating because by using dynamic you'll loose type safety (risking runtime exceptions) and it'll decrease performance.

    If have no idea about your app domain, but if this aspect is import for you, I would change some things and try generic out parameters.

    public interface IProcessor<out T, out TU> where T : DocumentValidation {
        HtmlContent RetrieveDocument(SearchItem item);
        bool ValidateObject(DocumentValidation obj);
        T ProcessFrom(HtmlContent content);
        TU ProcessTo(DocumentValidation source);
    }
    

    Factory:

    public static IProcessor<DocumentValidation, ProcessResult> Create(string at) {
      if (condition(at))
        return new StandardDocumentProcessor();
      else
        return new ModDocumentProcessor();
      }
    

    Note that I removed the SaveTo method because it does not fit into this pattern. Move it to another interface if you require it anyway. ProcessResult is a base class / interface for XmlDocument.

    Just another note: everything would be simpler if you wouldn't use generics at all and work with inheritance / base classes. The factory pattern is commonly used to hide and encapsulate implementation details and types, including some generic parameters. If you want to get type information out of your factory, perhaps it isn't the best idea to use a factory.