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.
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.