Dependence injection of a general type: how to introduce T

I want to process different types of documents in the same way in my application Therefore: I have such a common interface.

public interface IDocHandler<T>where T: class { T Document { get;set;} void Load(T doc); void Load(string PathToDoc); void Execute(); void Execute(T doc); } 

And for different types of documents, I implement this interface.

eg:

 public class FinanceDocumentProcessor:IDocumentHandler<ReportDocument> {} public class MarketingDocumentProcessor:IDocumentHandler<MediaDocument> {} 

Then, of course, I can do something like this:

 IDocumentHandler<ReportDocument> docProc= new FinanceDocumentProcessor(); 

It would be interesting to know how I could introduce T at runtime to make the line above loosely coupled ...

 IDocumentHandler<ReportDocument> docProc = container.resolve("FinanceDocumentProcessor()); 

but I want to decide for each configuration I want to have my FinanceDomcumentProcessor or my MarketingDocumentProcessor ... so I would have to type T to the left site too ... Since I have to use C # 2.0, I can’t use the magic word “var”, which in this case would help a lot ... but how can I create this to be open and flexible ...


Sorry for the misunderstanding and thanks for all the comments, but I have another example for my call (maybe I use the wrong design for this) ... But I give it a try: in the same situation, but in a different explanation

Example image I have:

ReportingService, Crystal, ListAndLabel Three different types of reports. I have a generic Handler IReportHandler<T> (will be the same as above), this Handler provides all the functions for processing a report document. for example

 ChrystalReportHandler:IReportHandler<CrystalReportDocument> 

Now I want to use the Unity platform (or some other framework) for dependency injection, to decide through the configuration whether I want to use Crystal, Reportingservices or List and Label.

When I specify my mapping, I can enter my ChrystalReportHandler , but how can I enter T on the left or better the word Type ReportDocument .

 IReportHandler<T (this needs also to be injected)> = IOContainer.Resolve(MyMappedType here) 

My problem is the left site, of course, because it is associated with the type, but I have a mapping ... can I create an object based on the mapping and assign a displayed type? or basically enter T from the left side too? Or this approach is not suitable for this situation.

+4
source share
3 answers

I think that with your current design you are creating a “dependency” between the IDocumentHandler and the specific document ( ReportDocument or MediaDocument ), and therefore, if you want to use the IDocumentHandler<ReportDocument or MediaDocument> directly in your code, you should assume that your container will give that’s for you. In this case, the container should not be responsible for resolving the type of document.

Could you change your design?

 public interface IDocumentHandler { IDocument Document { get; set; } void Load(IDocument doc); void Load(string PathToDoc); void Execute(); void Execute(IDocument doc); } public class IDocument { } public class ReportDocument : IDocument { } public class MediaDocument : IDocument { } public class FinanceDocumentProcessor : IDocumentHandler { } public class MarketingDocumentProcessor : IDocumentHandler { } 
+2
source

You need to use a non-common interface on the left side.

Try:

 public interface IDocumentHandler { } public interface IDocumentHandler<T> : IDocumentHandler { } 

This will create two interfaces. Put everything common, non-T-specific in the base interface, and everything else in the generic.

Since the code into which you want to resolve the object in which you do not know the type of processor, you still could not name any T-specific code, so you will not lose anything using a non-common interface.


Change I noticed that my answer was omitted. It would be nice if the confusing people left a comment on why they did it. I do not care about the point of reputation, it’s just a slight noise at the moment, but if there is something serious in the answer, then I would like to know if I could either delete the answer (if it does not correspond to the purpose) or correct it.

Now in this case, I suspect that either the original questionnaire rejected it, and thus either did not post enough information, so that he really asked about something other than what he asked for, or he did not quite understand my answer which is understandable because it was a little short, or one who did not understand it dropped it, again for the same reason.

Now to clarify.

You cannot enter anything “on the left side”. It's impossible. This code must compile, be correct, and be 100% "there" at compile time. You cannot say "we will tell you that T is at run time" for this part. It is simply not possible.

So, the only thing you have left is to completely remove T. Make code that uses a dependency independent of T in general. Or at least use reflection to find out what T is and what it does based on that knowledge.

What can you do. You cannot force the code on the left to change itself depending on what you return from the method on the right.

It's impossible.

Hence my answer.

+1
source

If you understand correctly, you have two options.

  • If you have an IDocHandler interface and several classes, you need to register each type, for example:

    container.AddComponent> (TypeOf (FooHandler));

  • If you have one DocHandler class, you can register using the open open type component

    container.AddComponent (typeof (IDocHandler <>), typeof (DocHandler <>));

then every time you enable IDocHandler, you get an instance of DocHandler, and when you enable IDocHandler, you get DocHandler

hope that helps

+1
source

All Articles