2008-12-10 10 views
4

Je souhaite traiter de la même manière différents types de documents dans mon application Par conséquent: J'ai une interface générique comme celle-ci.injection de dépendance de type générique: comment injecter T

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); 

} 

Et pour différents types de documents, j'implémente cette interface.

par exemple:

public class FinanceDocumentProcessor:IDocumentHandler<ReportDocument> 
{} 


public class MarketingDocumentProcessor:IDocumentHandler<MediaDocument> 
{} 

alors je peux faire bien sûr quelque chose comme ceci:

IDocumentHandler<ReportDocument> docProc= new FinanceDocumentProcessor(); 

Il serait interessting de savoir comment je pourrais injecter T lors de l'exécution pour que la ligne ci-dessus loosly couplé ...

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

mais je veux décider par configuration si je veux avoir mon FinanceDomcume ntProcessor ou mon MarketingDocumentProcessor ... donc je devrais injecter T sur le site de gauche, aussi ... Puisque je dois utiliser C# 2.0 je ne peux pas utiliser le mot magique "var" qui aiderait beaucoup dans ce cas. .. mais comment puis-je concevoir que ce soit ouvert et flexible ...


Désolé pour le malentendu et merci pour tous les commentaires mais j'ai un autre exemple pour mon défi (peut-être que je me sers de la mauvaise conception pour que) ... mais je donne un essai: même situation mais différente Explication

Exemple d'image je:

ReportingService, Crystal, ListAndLabel Trois types de document de rapport différents. J'ai un gestionnaire générique IReportHandler<T> (serait le même que ci-dessus) ce gestionnaire fournit toutes les fonctionnalités pour gérer un document de rapport. pour l'exemple

ChrystalReportHandler:IReportHandler<CrystalReportDocument> 

Maintenant, je veux utiliser un cadre comme l'unité (ou un cadre d'autre) pour l'injection de dépendance de décider par la configuration si je veux utiliser Crystal, Reportingservices Liste et étiquette.

Lorsque je spécifie ma cartographie, je peux injecter mon ChrystalReportHandler mais comment puis-je injecter T sur le côté gauche ou dans un meilleur mot Le type de ReportDocument.

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

mon problème est le site gauche bien sûr, car il est couplé au type, mais je me cartographie ... serait-il possible de générer un objet basé sur la cartographie et attribuer le type cartographié? ou en gros injecter T sur le côté gauche, aussi? Ou cette approche ne convient-elle pas à cette situation?

Répondre

1

Vous devez utiliser une interface non générique sur le côté gauche.

Essayez:

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

Cela va créer deux interfaces. Mettez tout ce qui est commun, non spécifique à T dans l'interface de base, et tout le reste dans le générique.Comme le code dans lequel vous voulez résoudre un objet, pour lequel vous ne connaissez pas le type de processeur, vous ne pouvez pas appeler le code spécifique T de toute façon, donc vous ne perdrez rien en utilisant l'interface non générique.


Modifier: Je remarque que ma réponse a été downvoted. Ce serait bien si les gens downvoting choses laisserait un commentaire pourquoi ils l'ont fait. Je ne me soucie pas du point de réputation, ce n'est qu'un bruit mineur à ce stade, mais s'il y a quelque chose qui ne va pas dans la réponse, alors j'aimerais savoir si je peux supprimer la réponse (si c'est loin de la cible) ou corrigez-le. Maintenant, dans ce cas, je soupçonne que le premier interrogé l'a déprécié, et que, par conséquent, il n'a pas affiché suffisamment d'informations, de sorte qu'il demande autre chose que ce qu'il a demandé, ou il n'a pas tout à fait compris ma réponse, ce qui est compréhensible étant donné que c'était un peu court, ou que quelqu'un qui ne l'a pas compris l'a rabaissé, encore une fois pour la même raison.

Maintenant, pour élaborer.

Vous ne pouvez rien injecter "sur le côté gauche". Ce n'est pas possible. Ce code doit compiler, être correct, et être 100% "là" à la compilation. Vous ne pouvez pas dire "nous vous dirons ce que T est à l'exécution" pour cette partie. Ce n'est simplement pas possible.

Donc la seule chose qui vous reste est d'enlever le T tout à fait. Rendre le code qui utilise la dépendance ne dépend pas de T, du tout. Ou, à tout le moins, utilisez la réflexion pour découvrir ce qu'est T et ce que vous faites en fonction de ces connaissances.

C'est tout ce que vous pouvez faire. Vous ne pouvez pas faire en sorte que le code sur le côté gauche change lui-même en fonction de ce que vous renvoyez d'une méthode sur le côté droit.

Ce n'est pas possible.

D'où ma réponse.

2

Je pense que votre conception actuelle, vous créez une « dépendance » entre IDocumentHandler et d'un document spécifique (ReportDocument ou MediaDocument) et donc si vous voulez utiliser IDocumentHandler<ReportDocument or MediaDocument> directement dans votre code, vous devez supposer que votre conteneur donnera c'est juste ça. Le conteneur ne devrait pas être responsable de la résolution du type de document dans ce cas.

Souhaitez-vous changer votre design comme celui-ci?

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 { } 
1

Si je vous ai bien compris, vous avez deux options.

  1. si vous avez une interface IDocHandler et plusieurs cours de mise en œuvre, vous devez vous enregistrer chaque de type explicitement, comme ceci:

    container.AddComponent> (typeof (FooHandler));

  2. si vous avez une classe DocHandler vous pouvez vous inscrire à l'aide de composants type générique ouvert

    contenant

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

chaque fois que vous résoudre IDocHandler vous obtiendrez une instance de DocHandler et quand vous résolvez IDocHandler vous obtiendrez DocHandler

espoir qui aide